var Yocto = function() {
    function t(t) {
        return null == t ? String(t) : A[L.call(t)] || "object"
    }
    function e(e) {
        return "function" == t(e)
    }
    function n(t) {
        return null != t && t == t.window
    }
    function r(t) {
        return null != t && t.nodeType == t.DOCUMENT_NODE
    }
    function i(e) {
        return "object" == t(e)
    }
    function o(t) {
        return i(t) && !n(t) && Object.getPrototypeOf(t) == Object.prototype
    }
    function s(t) {
        return "number" == typeof t.length
    }
    function a(t) {
        return T.call(t, function(t) {
            return null != t
        })
    }
    function u(t) {
        return t.length > 0 ? y.fn.concat.apply([], t) : t
    }
    function c(t) {
        return t in S ? S[t] : S[t] = new RegExp("(^|\\s)" + t + "(\\s|$)")
    }
    function l(t) {
        return "children"in t ? j.call(t.children) : y.map(t.childNodes, function(t) {
            return 1 == t.nodeType ? t : void 0
        })
    }
    function f(t, e) {
        return null == e ? y(t) : y(t).filter(e)
    }
    function h(t, n, r, i) {
        return e(n) ? n.call(t, r, i) : n
    }
    function p(t, e, n) {
        null == n ? t.removeAttribute(e) : t.setAttribute(e, n)
    }
    function d(t, e) {
        var n = t.className
          , r = n && n.baseVal !== v;
        return e === v ? r ? n.baseVal : n : void (r ? n.baseVal = e : t.className = e)
    }
    function m(t) {
        var e;
        try {
            return t ? "true" == t || ("false" == t ? !1 : "null" == t ? null : /^0/.test(t) || isNaN(e = Number(t)) ? /^[\[\{]/.test(t) ? y.parseJSON(t) : t : e) : t
        } catch (n) {
            return t
        }
    }
    var v, g, y, x, b, w, E = [], j = E.slice, T = E.filter, N = window, C = N.document, P = {}, S = {}, O = /^\s*<(\w+|!)[^>]*>/, A = {}, L = A.toString, $ = {}, D = Array.isArray;
    return $.matches = function(t, e) {
        var n = C.createElement("div");
        if (!e || !t || 1 !== t.nodeType)
            return !1;
        var r = t.webkitMatchesSelector || t.matchesSelector;
        if (r)
            return r.call(t, e);
        var i, o = t.parentNode, s = !o;
        return s && (o = n).appendChild(t),
        i = ~$.qsa(o, e).indexOf(t),
        s && n.removeChild(t),
        i
    }
    ,
    b = function(t) {
        return t.replace(/-+(.)?/g, function(t, e) {
            return e ? e.toUpperCase() : ""
        })
    }
    ,
    w = function(t) {
        return T.call(t, function(e, n) {
            return t.indexOf(e) == n
        })
    }
    ,
    $.fragment = function(t, e, n) {
        var r, i, s, a = C.createElement("table"), u = C.createElement("tr"), c = {
            tr: C.createElement("tbody"),
            tbody: a,
            thead: a,
            tfoot: a,
            td: u,
            th: u,
            "*": C.createElement("div")
        }, l = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, f = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, h = ["val", "css", "html", "text", "data", "width", "height", "offset"];
        return f.test(t) && (r = y(C.createElement(RegExp.$1))),
        r || (t.replace && (t = t.replace(l, "<$1></$2>")),
        e === v && (e = O.test(t) && RegExp.$1),
        e in c || (e = "*"),
        s = c[e],
        s.innerHTML = "" + t,
        r = y.each(j.call(s.childNodes), function() {
            s.removeChild(this)
        })),
        o(n) && (i = y(r),
        y.each(n, function(t, e) {
            h.indexOf(t) > -1 ? i[t](e) : i.attr(t, e)
        })),
        r
    }
    ,
    $.Z = function(t, e) {
        return t = t || [],
        t.__proto__ = y.fn,
        t.selector = e || "",
        t
    }
    ,
    $.isZ = function(t) {
        return t instanceof $.Z
    }
    ,
    $.init = function(t, n) {
        var r;
        if (!t)
            return $.Z();
        if ("string" == typeof t)
            if (t = t.trim(),
            "<" == t[0] && O.test(t))
                r = $.fragment(t, RegExp.$1, n),
                t = null;
            else {
                if (n !== v)
                    return y(n).find(t);
                r = $.qsa(C, t)
            }
        else {
            if (e(t))
                return y(C).ready(t);
            if ($.isZ(t))
                return t;
            if (D(t))
                r = a(t);
            else if (i(t))
                r = [t],
                t = null;
            else if (O.test(t))
                r = $.fragment(t.trim(), RegExp.$1, n),
                t = null;
            else {
                if (n !== v)
                    return y(n).find(t);
                r = $.qsa(C, t)
            }
        }
        return $.Z(r, t)
    }
    ,
    y = function(t, e) {
        return $.init(t, e)
    }
    ,
    y.extend = function(t) {
        var e, n = function(t, e, r) {
            for (g in e)
                r && (o(e[g]) || D(e[g])) ? (o(e[g]) && !o(t[g]) && (t[g] = {}),
                D(e[g]) && !D(t[g]) && (t[g] = []),
                n(t[g], e[g], r)) : e[g] !== v && (t[g] = e[g])
        }, r = j.call(arguments, 1);
        return "boolean" == typeof t && (e = t,
        t = r.shift()),
        r.forEach(function(r) {
            n(t, r, e)
        }),
        t
    }
    ,
    $.qsa = function(t, e) {
        var n, i = "#" == e[0], o = !i && "." == e[0], s = i || o ? e.slice(1) : e, a = /^[\w-]*$/.test(s);
        return r(t) && a && i ? (n = t.getElementById(s)) ? [n] : [] : 1 !== t.nodeType && 9 !== t.nodeType ? [] : j.call(a && !i ? o ? t.getElementsByClassName(s) : t.getElementsByTagName(e) : t.querySelectorAll(e))
    }
    ,
    y.contains = function(t, e) {
        return t !== e && t.contains(e)
    }
    ,
    y.type = t,
    y.isFunction = e,
    y.isWindow = n,
    y.isArray = D,
    y.isPlainObject = o,
    y.inArray = function(t, e, n) {
        return E.indexOf.call(e, t, n)
    }
    ,
    y.camelCase = b,
    y.trim = function(t) {
        return null == t ? "" : String.prototype.trim.call(t)
    }
    ,
    y.uuid = 0,
    y.support = {},
    y.expr = {},
    y.map = function(t, e) {
        var n, r, i, o = [];
        if (s(t))
            for (r = 0; r < t.length; r++)
                n = e(t[r], r),
                null != n && o.push(n);
        else
            for (i in t)
                n = e(t[i], i),
                null != n && o.push(n);
        return u(o)
    }
    ,
    y.each = function(t, e) {
        var n, r;
        if (s(t)) {
            for (n = 0; n < t.length; n++)
                if (e.call(t[n], n, t[n]) === !1)
                    return t
        } else
            for (r in t)
                if (e.call(t[r], r, t[r]) === !1)
                    return t;
        return t
    }
    ,
    y.grep = function(t, e) {
        return T.call(t, e)
    }
    ,
    y.parseJSON = JSON.parse,
    y.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(t, e) {
        A["[object " + e + "]"] = e.toLowerCase()
    }),
    y.fn = {
        forEach: E.forEach,
        reduce: E.reduce,
        push: E.push,
        sort: E.sort,
        indexOf: E.indexOf,
        concat: E.concat,
        map: function(t) {
            return y(y.map(this, function(e, n) {
                return t.call(e, n, e)
            }))
        },
        slice: function() {
            return y(j.apply(this, arguments))
        },
        ready: function(t) {
            var e = /complete|loaded|interactive/;
            return e.test(C.readyState) ? t(y) : C.addEventListener("DOMContentLoaded", function() {
                t(y)
            }, !1),
            this
        },
        get: function(t) {
            return t === v ? j.call(this) : this[t >= 0 ? t : t + this.length]
        },
        toArray: function() {
            return this.get()
        },
        size: function() {
            return this.length
        },
        remove: function() {
            return this.each(function() {
                null != this.parentNode && this.parentNode.removeChild(this)
            })
        },
        each: function(t) {
            return E.every.call(this, function(e, n) {
                return t.call(e, n, e) !== !1
            }),
            this
        },
        filter: function(t) {
            return e(t) ? this.not(this.not(t)) : y(T.call(this, function(e) {
                return $.matches(e, t)
            }))
        },
        add: function(t, e) {
            return y(w(this.concat(y(t, e))))
        },
        is: function(t) {
            return this.length > 0 && $.matches(this[0], t)
        },
        not: function(t) {
            var n = [];
            if (e(t) && t.call !== v)
                this.each(function(e) {
                    t.call(this, e) || n.push(this)
                });
            else {
                var r = "string" == typeof t ? this.filter(t) : s(t) && e(t.item) ? j.call(t) : y(t);
                this.forEach(function(t) {
                    r.indexOf(t) < 0 && n.push(t)
                })
            }
            return y(n)
        },
        has: function(t) {
            return this.filter(function() {
                return i(t) ? y.contains(this, t) : y(this).find(t).size()
            })
        },
        eq: function(t) {
            return -1 === t ? this.slice(t) : this.slice(t, +t + 1)
        },
        first: function() {
            var t = this[0];
            return t && !i(t) ? t : y(t)
        },
        last: function() {
            var t = this[this.length - 1];
            return t && !i(t) ? t : y(t)
        },
        find: function(t) {
            var e, n = this;
            return e = "object" == typeof t ? y(t).filter(function() {
                var t = this;
                return E.some.call(n, function(e) {
                    return y.contains(e, t)
                })
            }) : 1 == this.length ? y($.qsa(this[0], t)) : this.map(function() {
                return $.qsa(this, t)
            })
        },
        closest: function(t) {
            return y($.matches(this[0], t) ? this[0] : this.parents(t).get(0))
        },
        parents: function(t) {
            for (var e = [], n = this; n.length > 0; )
                n = y.map(n, function(t) {
                    return (t = t.parentNode) && !r(t) && e.indexOf(t) < 0 ? (e.push(t),
                    t) : void 0
                });
            return f(e, t)
        },
        parent: function(t) {
            return f(w(this.pluck("parentNode")), t)
        },
        children: function(t) {
            return f(this.map(function() {
                return l(this)
            }), t)
        },
        siblings: function(t) {
            return f(this.map(function(t, e) {
                return T.call(l(e.parentNode), function(t) {
                    return t !== e
                })
            }), t)
        },
        pluck: function(t) {
            return y.map(this, function(e) {
                return e[t]
            })
        },
        show: function() {
            var t = function(t) {
                return getComputedStyle(t, "").getPropertyValue("display")
            };
            return this.each(function() {
                if ("none" == this.style.display && (this.style.display = ""),
                "none" == t(this)) {
                    var e = function(e) {
                        var n, r;
                        return P[e] || (n = C.createElement(e),
                        C.body.appendChild(n),
                        r = t(n),
                        n.parentNode.removeChild(n),
                        "none" == r && (r = "block"),
                        P[e] = r),
                        P[e]
                    };
                    this.style.display = e(this.nodeName)
                }
            })
        },
        replaceWith: function(t) {
            return this.before(t).remove()
        },
        clone: function() {
            return this.map(function() {
                return this.cloneNode(!0)
            })
        },
        hide: function() {
            return this.css("display", "none")
        },
        toggle: function(t) {
            return this.each(function() {
                var e = y(this);
                (t === v ? "none" == e.css("display") : t) ? e.show() : e.hide()
            })
        },
        prev: function(t) {
            return y(this.pluck("previousElementSibling")).filter(t || "*")
        },
        next: function(t) {
            return y(this.pluck("nextElementSibling")).filter(t || "*")
        },
        html: function(t) {
            return 0 === arguments.length ? this.length > 0 ? this[0].innerHTML : null : this.each(function(e) {
                var n = this.innerHTML;
                this.innerHTML = "",
                y(this).append(h(this, t, e, n))
            })
        },
        text: function(t) {
            return 0 === arguments.length ? this.length > 0 ? this[0].textContent : null : this.each(function() {
                this.textContent = t === v ? "" : "" + t
            })
        },
        attr: function(t, e) {
            var n;
            return "string" == typeof t && e === v ? 0 == this.length || 1 !== this[0].nodeType ? v : "value" == t && "INPUT" == this[0].nodeName ? this.val() : !(n = this[0].getAttribute(t)) && t in this[0] ? this[0][t] : n : this.each(function(n) {
                if (1 === this.nodeType)
                    if (i(t))
                        for (g in t)
                            p(this, g, t[g]);
                    else
                        p(this, t, h(this, e, n, this.getAttribute(t)))
            })
        },
        removeAttr: function(t) {
            return this.each(function() {
                1 === this.nodeType && p(this, t)
            })
        },
        data: function(t, e) {
            var n = /([A-Z])/g
              , r = this.attr("data-" + t.replace(n, "-$1").toLowerCase(), e);
            return null !== r ? m(r) : v
        },
        val: function(t) {
            return 0 === arguments.length ? this[0] && (this[0].multiple ? y(this[0]).find("option").filter(function() {
                return this.selected
            }).pluck("value") : this[0].value) : this.each(function(e) {
                this.value = h(this, t, e, this.value)
            })
        },
        offset: function(t) {
            if (t)
                return this.each(function(e) {
                    var n = y(this)
                      , r = h(this, t, e, n.offset())
                      , i = n.offsetParent().offset()
                      , o = {
                        top: r.top - i.top,
                        left: r.left - i.left
                    };
                    "static" == n.css("position") && (o.position = "relative"),
                    n.css(o)
                });
            if (0 == this.length)
                return null;
            var e = this[0].getBoundingClientRect();
            return {
                left: e.left + window.pageXOffset,
                top: e.top + window.pageYOffset,
                width: Math.round(e.width),
                height: Math.round(e.height)
            }
        },
        css: function(e, n) {
            var r = function(t, e) {
                var n = {
                    "column-count": 1,
                    columns: 1,
                    "font-weight": 1,
                    "line-height": 1,
                    opacity: 1,
                    "z-index": 1,
                    zoom: 1
                };
                return "number" != typeof e || n[i(t)] ? e : e + "px"
            }
              , i = function(t) {
                return t.replace(/::/g, "/").replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2").replace(/([a-z\d])([A-Z])/g, "$1_$2").replace(/_/g, "-").toLowerCase()
            };
            if (arguments.length < 2) {
                var o = this[0];
                if (!o)
                    return;
                var s = getComputedStyle(o, "");
                if ("string" == typeof e)
                    return o.style[b(e)] || s.getPropertyValue(e);
                if (D(e)) {
                    var a = {};
                    return y.each(D(e) ? e : [e], function(t, e) {
                        a[e] = o.style[b(e)] || s.getPropertyValue(e)
                    }),
                    a
                }
            }
            var u = "";
            if ("string" == t(e))
                n || 0 === n ? u = i(e) + ":" + r(e, n) : this.each(function() {
                    this.style.removeProperty(i(e))
                });
            else
                for (g in e)
                    e[g] || 0 === e[g] ? u += i(g) + ":" + r(g, e[g]) + ";" : this.each(function() {
                        this.style.removeProperty(i(g))
                    });
            return this.each(function() {
                this.style.cssText += ";" + u
            })
        },
        index: function(t) {
            return t ? this.indexOf(y(t)[0]) : this.parent().children().indexOf(this[0])
        },
        hasClass: function(t) {
            return t ? E.some.call(this, function(t) {
                return this.test(d(t))
            }, c(t)) : !1
        },
        addClass: function(t) {
            return t ? this.each(function(e) {
                x = [];
                var n = d(this)
                  , r = h(this, t, e, n);
                r.split(/\s+/g).forEach(function(t) {
                    y(this).hasClass(t) || x.push(t)
                }, this),
                x.length && d(this, n + (n ? " " : "") + x.join(" "))
            }) : this
        },
        removeClass: function(t) {
            return this.each(function(e) {
                return t === v ? d(this, "") : (x = d(this),
                h(this, t, e, x).split(/\s+/g).forEach(function(t) {
                    x = x.replace(c(t), " ")
                }),
                void d(this, x.trim()))
            })
        },
        toggleClass: function(t, e) {
            return t ? this.each(function(n) {
                var r = y(this)
                  , i = h(this, t, n, d(this));
                i.split(/\s+/g).forEach(function(t) {
                    (e === v ? !r.hasClass(t) : e) ? r.addClass(t) : r.removeClass(t)
                })
            }) : this
        },
        scrollTop: function(t) {
            if (this.length) {
                var e = "scrollTop"in this[0];
                return t === v ? e ? this[0].scrollTop : this[0].pageYOffset : this.each(e ? function() {
                    this.scrollTop = t
                }
                : function() {
                    this.scrollTo(this.scrollX, t)
                }
                )
            }
        }
    },
    y.fn.detach = y.fn.remove,
    ["width", "height"].forEach(function(t) {
        var e = t.replace(/./, function(t) {
            return t[0].toUpperCase()
        });
        y.fn[t] = function(i) {
            var o, s = this[0];
            return i === v ? n(s) ? s["inner" + e] : r(s) ? s.documentElement["scroll" + e] : (o = this.offset()) && o[t] : this.each(function(e) {
                s = y(this),
                s.css(t, h(this, i, e, s[t]()))
            })
        }
    }),
    ["after", "prepend", "before", "append"].forEach(function(e, n) {
        var r = n % 2;
        y.fn[e] = function() {
            var e, i, o = y.map(arguments, function(n) {
                return e = t(n),
                "object" == e || "array" == e || null == n ? n : $.fragment(n)
            }), s = this.length > 1;
            return o.length < 1 ? this : this.each(function(t, e) {
                i = r ? e : e.parentNode,
                e = 0 == n ? e.nextSibling : 1 == n ? e.firstChild : 2 == n ? e : null;
                var a = function(t, e) {
                    e(t);
                    for (var n in t.childNodes)
                        a(t.childNodes[n], e)
                };
                o.forEach(function(t) {
                    if (s)
                        t = t.cloneNode(!0);
                    else if (!i)
                        return y(t).remove();
                    a(i.insertBefore(t, e), function(t) {
                        null == t.nodeName || "SCRIPT" !== t.nodeName.toUpperCase() || t.type && "text/javascript" !== t.type || t.src || N.eval.call(N, t.innerHTML)
                    })
                })
            })
        }
        ,
        y.fn[r ? e + "To" : "insert" + (n ? "Before" : "After")] = function(t) {
            return y(t)[e](this),
            this
        }
    }),
    $.Z.prototype = y.fn,
    $.uniq = w,
    $.deserializeValue = m,
    y.zepto = $,
    y
}();
void 0 === window.$ && (window.$ = Yocto),
window.Yocto = Yocto,
window.Zepto = Yocto,
function(t) {
    function e(t) {
        return t._zid || (t._zid = h++)
    }
    function n(t, n, o, s) {
        if (n = r(n),
        n.ns)
            var a = i(n.ns);
        return (v[e(t)] || []).filter(function(t) {
            return !(!t || n.e && t.e != n.e || n.ns && !a.test(t.ns) || o && e(t.fn) !== e(o) || s && t.sel != s)
        })
    }
    function r(t) {
        var e = ("" + t).split(".");
        return {
            e: e[0],
            ns: e.slice(1).sort().join(" ")
        }
    }
    function i(t) {
        return new RegExp("(?:^| )" + t.replace(" ", " .* ?") + "(?: |$)")
    }
    function o(t, e) {
        return t.del && ("focus" === t.e || "blur" === t.e) || !!e
    }
    function s(t, n, i, s, a, c, h) {
        var p = e(t)
          , d = v[p] || (v[p] = []);
        n.split(/\s/).forEach(function(e) {
            if ("ready" == e)
                return f(document).ready(i);
            var n = r(e);
            n.fn = i,
            n.sel = a,
            n.del = c;
            var p = c || i;
            n.proxy = function(e) {
                if (e = u(e),
                !e.isImmediatePropagationStopped()) {
                    e.data = s;
                    var n = p.apply(t, e._args == l ? [e] : [e].concat(e._args));
                    return n === !1 && (e.preventDefault(),
                    e.stopPropagation()),
                    n
                }
            }
            ,
            n.i = d.length,
            d.push(n),
            "addEventListener"in t && t.addEventListener(n.e, n.proxy, o(n, h))
        })
    }
    function a(t, r, i, s, a) {
        var u = e(t);
        (r || "").split(/\s/).forEach(function(e) {
            n(t, e, i, s).forEach(function(e) {
                delete v[u][e.i],
                "removeEventListener"in t && t.removeEventListener(e.e, e.proxy, o(e, a))
            })
        })
    }
    function u(t, e) {
        return (e || !t.isDefaultPrevented) && (e || (e = t),
        f.each(w, function(n, r) {
            var i = e[n];
            t[n] = function() {
                return this[r] = y,
                i && i.apply(e, arguments)
            }
            ,
            t[r] = x
        }),
        (e.defaultPrevented !== l ? e.defaultPrevented : "returnValue"in e ? e.returnValue === !1 : e.getPreventDefault && e.getPreventDefault()) && (t.isDefaultPrevented = y)),
        t
    }
    function c(t) {
        var e, n = {
            originalEvent: t
        };
        for (e in t)
            b.test(e) || t[e] === l || (n[e] = t[e]);
        return u(n, t)
    }
    var l, f = t, h = 1, p = Array.prototype.slice, d = f.isFunction, m = function(t) {
        return "string" == typeof t
    }, v = {}, g = {};
    g.click = g.mousedown = g.mouseup = g.mousemove = "MouseEvents",
    f.event = {
        add: s,
        remove: a
    },
    f.proxy = function(t, n) {
        if (d(t)) {
            var r = function() {
                return t.apply(n, arguments)
            };
            return r._zid = e(t),
            r
        }
        if (m(n))
            return f.proxy(t[n], t);
        throw new TypeError("expected function")
    }
    ,
    f.fn.one = function(t, e, n, r) {
        return this.on(t, e, n, r, 1)
    }
    ;
    var y = function() {
        return !0
    }
      , x = function() {
        return !1
    }
      , b = /^([A-Z]|returnValue$|layer[XY]$)/
      , w = {
        preventDefault: "isDefaultPrevented",
        stopImmediatePropagation: "isImmediatePropagationStopped",
        stopPropagation: "isPropagationStopped"
    };
    f.fn.on = function(t, e, n, r, i) {
        var o, u, h = this;
        return t && m(t) && (f.fn.on.blurReg || (f.fn.on.blurReg = /(^blur)(\.|$)|(^focus)(\.|$)/),
        t = t.replace(f.fn.on.blurReg, function(t, e) {
            var n;
            return n = "blur" == e ? -1 === t.indexOf(".") ? "focusout" : "focusout." : -1 === t.indexOf(".") ? "focusin" : "focusin."
        })),
        t && !m(t) ? (f.each(t, function(t, r) {
            h.on(t, e, n, r, i)
        }),
        h) : (m(e) || d(r) || r === !1 || (r = n,
        n = e,
        e = l),
        (d(n) || n === !1) && (r = n,
        n = l),
        r === !1 && (r = x),
        f.gestures && f.gestures.list && f.gestures.list[t] && f.gestures.list[t](h),
        h.each(function(l, h) {
            i && (o = function(t) {
                return a(h, t.type, r),
                r.apply(this, arguments)
            }
            ),
            e && (u = function(t) {
                var n, i = f(t.target).closest(e, h).get(0);
                return i && i !== h ? (n = f.extend(c(t), {
                    currentTarget: i,
                    liveFired: h
                }),
                (o || r).apply(i, [n].concat(p.call(arguments, 1)))) : void 0
            }
            ),
            s(h, t, r, n, e, u || o)
        }))
    }
    ,
    f.fn.off = function(t, e, n) {
        var r = this;
        return t && !m(t) ? (f.each(t, function(t, n) {
            r.off(t, e, n)
        }),
        r) : (m(e) || d(n) || n === !1 || (n = e,
        e = l),
        n === !1 && (n = x),
        r.each(function() {
            a(this, t, n, e)
        }))
    }
    ,
    f.fn.trigger = function(t, e) {
        return t = m(t) || f.isPlainObject(t) ? f.Event(t) : u(t),
        t._args = e,
        this.each(function() {
            "dispatchEvent"in this ? this.dispatchEvent(t) : f(this).triggerHandler(t, e)
        })
    }
    ,
    f.fn.triggerHandler = function(t, e) {
        var r, i;
        return this.each(function(o, s) {
            r = c(m(t) ? f.Event(t) : t),
            r._args = e,
            r.target = s,
            f.each(n(s, t.type || t), function(t, e) {
                return i = e.proxy(r),
                r.isImmediatePropagationStopped() ? !1 : void 0
            })
        }),
        i
    }
    ,
    "focusin focusout load resize scroll unload click dblclick change select keydown keypress keyup error".split(" ").forEach(function(t) {
        f.fn[t] = function(e) {
            return e ? this.on(t, e) : this.trigger(t)
        }
    }),
    ["focus", "blur"].forEach(function(t) {
        f.fn[t] = function(e) {
            return e ? this.on(t, e) : this.each(function() {
                t = "blur" == t ? "focusout" : "focus" == t ? "focusin" : t,
                f(this).trigger(t)
            }),
            this
        }
    }),
    f.Event = function(t, e) {
        m(t) || (e = t,
        t = e.type);
        var n = document.createEvent(g[t] || "Events")
          , r = !0;
        if (e)
            for (var i in e)
                "bubbles" == i ? r = !!e[i] : n[i] = e[i];
        return n.initEvent(t, r, !0),
        u(n)
    }
}(Yocto),
function(t) {
    function e(t, e) {
        var n = e.context;
        return e.beforeSend.call(n, t, e) === !1 ? !1 : void 0
    }
    function n(t, e, n, r) {
        var o = n.context
          , s = "success";
        n.success.call(o, t, s, e),
        r && r(t),
        i(s, e, n)
    }
    function r(t, e, n, r, o, s) {
        s && s(new Error(t));
        var a = r.context;
        r.error.call(a, n, e, t),
        i(e, n, r)
    }
    function i(t, e, n) {
        var r = n.context;
        n.complete.call(r, e, t)
    }
    function o(t) {
        t()
    }
    function s() {}
    function a(t) {
        return t && (t = t.split(";", 2)[0]),
        t && (t == E ? "html" : t == w ? "json" : x.test(t) ? "script" : b.test(t) && "xml") || "text"
    }
    function u(t, e) {
        return "" == e ? t : (t + "&" + e).replace(/[&?]{1,2}/, "?")
    }
    function c(t) {
        t.processData && t.data && "string" != h.type(t.data) && (t.data = h.param(t.data, t.traditional)),
        !t.data || t.type && "GET" != t.type.toUpperCase() || (t.url = u(t.url, t.data),
        t.data = void 0)
    }
    function l(t, e, n, r) {
        return h.isFunction(e) && (r = n,
        n = e,
        e = void 0),
        h.isFunction(n) || (r = n,
        n = void 0),
        {
            url: t,
            data: e,
            success: n,
            dataType: r
        }
    }
    function f(t, e, n, r) {
        var i, o = h.isArray(e), s = h.isPlainObject(e);
        h.each(e, function(e, a) {
            i = h.type(a),
            r && (e = n ? r : r + "[" + (s || "object" == i || "array" == i ? e : "") + "]"),
            !r && o ? t.add(a.name, a.value) : "array" == i || !n && "object" == i ? f(t, a, n, e) : t.add(e, a)
        })
    }
    AJAX_UTIL = {
        ajaxBeforeSend: e,
        ajaxSuccess: n,
        ajaxError: r,
        DummyPromise: o
    };
    var h = t
      , p = AJAX_UTIL
      , d = 0
      , m = window.document
      , e = p.ajaxBeforeSend
      , n = p.ajaxSuccess
      , r = p.ajaxError;
    h.ajaxJSONP = function(t) {
        if (!("type"in t))
            return h.ajax && h.ajax(t);
        var i = window.Promise || p.DummyPromise
          , o = new i(function(i, o) {
            var s, a, u = t.jsonpCallback, c = (h.isFunction(u) ? u() : u) || "jsonp" + ++d, l = m.createElement("script"), f = window[c], p = {
                abort: v
            }, v = function(t) {
                o && o(new Error("jsonp error: " + t)),
                h(l).triggerHandler("error", t || "abort")
            };
            window[c] = function(t) {
                i && i(t),
                s = arguments
            }
            ,
            e(p, t) === !1 && v("abort"),
            h(l).on("load error", function(e, u) {
                clearTimeout(a),
                h(l).off().remove(),
                "error" != e.type && s ? n(s[0], p, t, i, o) : r("jsonp error", u || "error", p, t, i, o),
                window[c] = f,
                s && h.isFunction(f) && f(s[0]),
                f = s = void 0
            }),
            l.src = t.url.replace(/\?(.+)=\?/, "?$1=" + c),
            m.head.appendChild(l),
            t.timeout > 0 && (a = setTimeout(function() {
                v("timeout")
            }, t.timeout))
        }
        );
        return o
    }
    ;
    var v, g, h = t, p = AJAX_UTIL, y = /<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, x = /^(?:text|application)\/javascript/i, b = /^(?:text|application)\/xml/i, w = "application/json", E = "text/html", j = /^\s*$/, e = p.ajaxBeforeSend, n = p.ajaxSuccess, r = p.ajaxError;
    h.ajaxSettings = {
        type: "GET",
        beforeSend: s,
        success: s,
        error: s,
        complete: s,
        context: null,
        global: !0,
        xhr: function() {
            return new window.XMLHttpRequest
        },
        accepts: {
            script: "text/javascript, application/javascript, application/x-javascript",
            json: w,
            xml: "application/xml, text/xml",
            html: E,
            text: "text/plain"
        },
        crossDomain: !1,
        timeout: 0,
        processData: !0,
        cache: !0
    },
    h.ajax = function(t) {
        var i = h.extend({}, t || {})
          , o = window.Promise || p.DummyPromise;
        for (v in h.ajaxSettings)
            void 0 === i[v] && (i[v] = h.ajaxSettings[v]);
        i.crossDomain || (i.crossDomain = /^([\w-]+:)?\/\/([^\/]+)/.test(i.url) && RegExp.$2 != window.location.host),
        i.url || (i.url = window.location.toString()),
        c(i),
        i.cache === !1 && (i.url = u(i.url, "_=" + Date.now()));
        var l = i.dataType
          , f = /\?.+=\?/.test(i.url)
          , d = new o(function(t, o) {
            if ("jsonp" == l || f) {
                if (f || (i.url = u(i.url, i.jsonp ? i.jsonp + "=?" : i.jsonp === !1 ? "" : "callback=?")),
                t)
                    return t(h.ajaxJSONP(i));
                h.ajaxJSONP(i)
            }
            var c, p = i.accepts[l], d = {}, m = function(t, e) {
                d[t.toLowerCase()] = [t, e]
            }, v = /^([\w-]+:)\/\//.test(i.url) ? RegExp.$1 : window.location.protocol, y = i.xhr(), x = y.setRequestHeader;
            if (i.crossDomain || m("X-Requested-With", "XMLHttpRequest"),
            m("Accept", p || "*/*"),
            p && (p.indexOf(",") > -1 && (p = p.split(",", 2)[0]),
            y.overrideMimeType && y.overrideMimeType(p)),
            (i.contentType || i.contentType !== !1 && i.data && "GET" != i.type.toUpperCase()) && m("Content-Type", i.contentType || "application/x-www-form-urlencoded"),
            i.headers)
                for (g in i.headers)
                    m(g, i.headers[g]);
            y.setRequestHeader = m,
            y.onreadystatechange = function() {
                if (4 == y.readyState) {
                    y.onreadystatechange = s,
                    clearTimeout(c);
                    var e, u = !1;
                    if (y.status >= 200 && y.status < 300 || 304 == y.status || 0 == y.status && "file:" == v) {
                        l = l || a(y.getResponseHeader("content-type")),
                        e = y.responseText;
                        try {
                            "script" == l ? (1,
                            eval)(e) : "xml" == l ? e = y.responseXML : "json" == l && (e = j.test(e) ? null : h.parseJSON(e))
                        } catch (f) {
                            u = f,
                            "script" == l && (u.message = "eval remote script error: " + u.message)
                        }
                        u ? r(u, "parsererror", y, i, t, o) : n(e, y, i, t, o)
                    } else
                        r(y.statusText || null, y.status ? "error" : "abort", y, i, t, o)
                }
            }
            ,
            e(y, i) === !1 && (y.abort(),
            r("abort", "abort", y, i, t, o));
            var b = "async"in i ? i.async : !0;
            y.open(i.type, i.url, b);
            for (g in d)
                x.apply(y, d[g]);
            i.timeout > 0 && (y.timeout = i.timeout,
            y.ontimeout = function() {
                y.onreadystatechange = s,
                y.abort(),
                r("timeout", "timeout", y, i, t, o)
            }
            ),
            y.send(i.data ? i.data : null)
        }
        );
        return d
    }
    ,
    h.get = function() {
        return h.ajax(l.apply(null, arguments))
    }
    ,
    h.post = function() {
        var t = l.apply(null, arguments);
        return t.type = "POST",
        h.ajax(t)
    }
    ,
    h.getJSON = function() {
        var t = l.apply(null, arguments);
        return t.dataType = "json",
        h.ajax(t)
    }
    ,
    h.fn.load = function(t, e, n) {
        if (!this.length)
            return this;
        var r, i = this, o = t.split(/\s/), s = l(t, e, n), a = s.success;
        return o.length > 1 && (s.url = o[0],
        r = o[1]),
        s.success = function(t) {
            i.html(r ? h("<div>").html(t.replace(y, "")).find(r) : t),
            a && a.apply(i, arguments)
        }
        ,
        h.ajax(s),
        this
    }
    ;
    var T = encodeURIComponent;
    h.param = function(t, e) {
        var n = [];
        return n.add = function(t, e) {
            this.push(T(t) + "=" + T(e))
        }
        ,
        f(n, t, e),
        n.join("&").replace(/%20/g, "+")
    }
}(Yocto),
function(t) {
    function e(t) {
        return null != t && t.nodeType == t.DOCUMENT_NODE
    }
    function n(t, e, n, i) {
        return r.isFunction(e) ? e.call(t, n, i) : e
    }
    var r = t
      , i = {}
      , o = /^(?:body|html)$/i;
    i.fn = {
        wrap: function(t) {
            var e = r.isFunction(t);
            if (this[0] && !e)
                var n = r(t).get(0)
                  , i = n.parentNode || this.length > 1;
            return this.each(function(o) {
                r(this).wrapAll(e ? t.call(this, o) : i ? n.cloneNode(!0) : n)
            })
        },
        wrapAll: function(t) {
            if (this[0]) {
                r(this[0]).before(t = r(t));
                for (var e; (e = t.children()).length; )
                    t = e.first();
                r(t).append(this)
            }
            return this
        },
        wrapInner: function(t) {
            var e = r.isFunction(t);
            return this.each(function(n) {
                var i = r(this)
                  , o = i.contents()
                  , s = e ? t.call(this, n) : t;
                o.length ? o.wrapAll(s) : i.append(s)
            })
        },
        unwrap: function() {
            return this.parent().each(function() {
                r(this).replaceWith(r(this).children())
            }),
            this
        },
        closest: function(t, n) {
            var i = this[0]
              , o = !1;
            for ("object" == typeof t && (o = r(t)); i && !(o ? o.indexOf(i) >= 0 : r.zepto.matches(i, t)); )
                i = i !== n && !e(i) && i.parentNode;
            return r(i)
        },
        contents: function() {
            return this.map(function() {
                return [].slice.call(this.childNodes)
            })
        },
        empty: function() {
            return this.each(function() {
                this.innerHTML = ""
            })
        },
        scrollLeft: function(t) {
            if (this.length) {
                var e = "scrollLeft"in this[0];
                return void 0 === t ? e ? this[0].scrollLeft : this[0].pageXOffset : this.each(e ? function() {
                    this.scrollLeft = t
                }
                : function() {
                    this.scrollTo(t, this.scrollY)
                }
                )
            }
        },
        position: function() {
            if (this.length) {
                var t = this[0]
                  , e = this.offsetParent()
                  , n = this.offset()
                  , i = o.test(e[0].nodeName) ? {
                    top: 0,
                    left: 0
                } : e.offset();
                return n.top -= parseFloat(r(t).css("margin-top")) || 0,
                n.left -= parseFloat(r(t).css("margin-left")) || 0,
                i.top += parseFloat(r(e[0]).css("border-top-width")) || 0,
                i.left += parseFloat(r(e[0]).css("border-left-width")) || 0,
                {
                    top: n.top - i.top,
                    left: n.left - i.left
                }
            }
        },
        offsetParent: function() {
            return this.map(function() {
                for (var t = this.offsetParent || document.body; t && !o.test(t.nodeName) && "static" == r(t).css("position"); )
                    t = t.offsetParent;
                return t
            })
        },
        bind: function(t, e, n) {
            return this.on(t, e, n)
        },
        unbind: function(t, e) {
            return this.off(t, e)
        },
        delegate: function(t, e, n) {
            return this.on(e, t, n)
        },
        undelegate: function(t, e, n) {
            return this.off(e, t, n)
        },
        live: function(t, e) {
            return r(document.body).delegate(this.selector, t, e),
            this
        },
        die: function(t, e) {
            return r(document.body).undelegate(this.selector, t, e),
            this
        },
        prop: function(t, e) {
            return void 0 === e ? this[0] && this[0][t] : this.each(function(r) {
                this[t] = n(this, e, r, this[t])
            })
        },
        serializeArray: function() {
            var t, e = [];
            return r(Array.prototype.slice.call(this.get(0).elements)).each(function() {
                t = r(this);
                var n = t.attr("type");
                "fieldset" != this.nodeName.toLowerCase() && !this.disabled && "submit" != n && "reset" != n && "button" != n && ("radio" != n && "checkbox" != n || this.checked) && e.push({
                    name: t.attr("name"),
                    value: t.val()
                })
            }),
            e
        },
        serialize: function() {
            var t = [];
            return this.serializeArray().forEach(function(e) {
                t.push(encodeURIComponent(e.name) + "=" + encodeURIComponent(e.value))
            }),
            t.join("&")
        },
        submit: function(t) {
            if (t)
                this.bind("submit", t);
            else if (this.length) {
                var e = r.Event("submit");
                this.eq(0).trigger(e),
                e.defaultPrevented || this.get(0).submit()
            }
            return this
        }
    },
    r.extend(r.fn, i.fn),
    ["width", "height"].forEach(function(t) {
        var e = t.replace(/./, function(t) {
            return t[0].toUpperCase()
        });
        r.fn["outer" + e] = function(e) {
            var n = this;
            if (n) {
                var r = n[t]()
                  , i = {
                    width: ["left", "right"],
                    height: ["top", "bottom"]
                };
                return i[t].forEach(function(t) {
                    e && (r += parseInt(n.css("margin-" + t), 10))
                }),
                r
            }
            return null
        }
    })
}(Yocto),
"undefined" != typeof exports && "undefined" != typeof module && (exports = module.exports = Yocto);
!function(a, b) {
    function c(a, b) {
        a = a.toString().split("."),
        b = b.toString().split(".");
        for (var c = 0; c < a.length || c < b.length; c++) {
            var d = parseInt(a[c], 10)
              , e = parseInt(b[c], 10);
            if (window.isNaN(d) && (d = 0),
            window.isNaN(e) && (e = 0),
            e > d)
                return -1;
            if (d > e)
                return 1
        }
        return 0
    }
    var d = a.document
      , e = a.navigator.userAgent
      , f = /iPhone|iPad|iPod/i.test(e)
      , g = /Android/i.test(e)
      , h = e.match(/(?:OS|Android)[\/\s](\d+[._]\d+(?:[._]\d+)?)/i)
      , i = e.match(/WindVane[\/\s](\d+[._]\d+[._]\d+)/)
      , j = Object.prototype.hasOwnProperty
      , k = b.windvane = a.WindVane || (a.WindVane = {})
      , l = (a.WindVane_Native,
    1)
      , m = []
      , n = 3
      , o = "hybrid"
      , p = "wv_hybrid"
      , q = "iframe_"
      , r = "suc_"
      , s = "err_"
      , t = "defer_"
      , u = "param_"
      , v = "chunk_"
      , w = 6e5
      , x = 6e5
      , y = 6e4;
    h = h ? (h[1] || "0.0.0").replace(/\_/g, ".") : "0.0.0",
    i = i ? (i[1] || "0.0.0").replace(/\_/g, ".") : "0.0.0";
    var z = {
        isAvailable: 1 === c(i, "0"),
        call: function(a, c, d, e, f, g) {
            var h, i;
            return "number" == typeof arguments[arguments.length - 1] && (g = arguments[arguments.length - 1]),
            "function" != typeof e && (e = null),
            "function" != typeof f && (f = null),
            b.promise && (i = b.promise.defer()),
            h = g > 0 ? setTimeout(function() {
                z.onFailure(h, {
                    ret: "HY_TIMEOUT"
                })
            }, g) : A.getSid(),
            A.registerCall(h, e, f, i),
            A.registerGC(h, g),
            A.callMethod(a, c, d, h),
            i ? i.promise : void 0
        },
        fireEvent: function(a, b, c) {
            var e = d.createEvent("HTMLEvents");
            e.initEvent(a, !1, !0),
            e.param = A.parseData(b || A.getData(c)),
            d.dispatchEvent(e)
        },
        getParam: function(a) {
            return A.getParam(a)
        },
        setData: function(a, b) {
            A.setData(a, b)
        },
        onSuccess: function(a, b) {
            A.onComplete(a, b, "success")
        },
        onFailure: function(a, b) {
            A.onComplete(a, b, "failure")
        }
    }
      , A = {
        params: {},
        chunks: {},
        calls: {},
        getSid: function() {
            return Math.floor(Math.random() * (1 << 50)) + "" + l++
        },
        buildParam: function(a) {
            return a && "object" == typeof a ? JSON.stringify(a) : a || ""
        },
        getParam: function(a) {
            return this.params[u + a] || ""
        },
        setParam: function(a, b) {
            this.params[u + a] = b
        },
        parseData: function(a) {
            var b;
            if (a && "string" == typeof a)
                try {
                    b = JSON.parse(a)
                } catch (c) {
                    b = {
                        ret: ["WV_ERR::PARAM_PARSE_ERROR"]
                    }
                }
            else
                b = a || {};
            return b
        },
        setData: function() {
            this.chunks[v + sid] = this.chunks[v + sid] || [],
            this.chunks[v + sid].push(chunk)
        },
        getData: function(a) {
            return this.chunks[v + a] ? this.chunks[v + a].join("") : ""
        },
        registerCall: function(a, b, c, d) {
            b && (this.calls[r + a] = b),
            c && (this.calls[s + a] = c),
            d && (this.calls[t + a] = d)
        },
        unregisterCall: function(a) {
            var b = r + a
              , c = s + a
              , d = t + a
              , e = {};
            return this.calls[b] && (e.success = this.calls[b],
            delete this.calls[b]),
            this.calls[c] && (e.failure = this.calls[c],
            delete this.calls[c]),
            this.calls[d] && (e.defer = this.calls[d],
            delete this.calls[d]),
            e
        },
        useIframe: function(a, b) {
            var c = q + a
              , e = m.pop();
            e || (e = d.createElement("iframe"),
            e.setAttribute("frameborder", "0"),
            e.style.cssText = "width:0;height:0;border:0;display:none;"),
            e.setAttribute("id", c),
            e.setAttribute("src", b),
            e.parentNode || setTimeout(function() {
                d.body.appendChild(e)
            }, 5)
        },
        retrieveIframe: function(a) {
            var b = q + a
              , c = d.querySelector("#" + b);
            m.length >= n ? d.body.removeChild(c) : m.push(c)
        },
        callMethod: function(a, b, c, d) {
            c = A.buildParam(c);
            var e = o + "://" + a + ":" + d + "/" + b + "?" + c;
            if (f)
                this.setParam(d, c),
                this.useIframe(d, e);
            else if (g) {
                var h = p + ":";
                window.prompt(e, h)
            }
        },
        registerGC: function(a, b) {
            var c = this
              , d = Math.max(b || 0, w)
              , e = Math.max(b || 0, y)
              , h = Math.max(b || 0, x);
            setTimeout(function() {
                c.unregisterCall(a)
            }, d),
            f ? setTimeout(function() {
                c.params[u + a] && delete c.params[u + a]
            }, e) : g && setTimeout(function() {
                c.chunks[v + a] && delete c.chunks[v + a]
            }, h)
        },
        onComplete: function(a, b, c) {
            clearTimeout(a);
            var d = this.unregisterCall(a)
              , e = d.success
              , h = d.failure
              , i = d.defer;
            b = b ? b : this.getData(a),
            b = this.parseData(b);
            var j = b.ret;
            "string" == typeof j && (b = b.value || b,
            b.ret || (b.ret = [j])),
            "success" === c ? (e && e(b),
            i && i.resolve(b)) : "failure" === c && (h && h(b),
            i && i.reject(b)),
            f ? (this.retrieveIframe(a),
            this.params[u + a] && delete this.params[u + a]) : g && this.chunks[v + a] && delete this.chunks[v + a]
        }
    };
    for (var B in z)
        j.call(k, B) || (k[B] = z[B])
}(window, window.lib || (window.lib = {}));
(function e(t, n, r) {
    function s(o, u) {
        if (!n[o]) {
            if (!t[o]) {
                var a = typeof require == "function" && require;
                if (!u && a)
                    return a(o, !0);
                if (i)
                    return i(o, !0);
                var f = new Error("Cannot find module '" + o + "'");
                throw f.code = "MODULE_NOT_FOUND",
                f;
            }
            var l = n[o] = {
                exports: {}
            };
            t[o][0].call(l.exports, function(e) {
                var n = t[o][1][e];
                return s(n ? n : e);
            }, l, l.exports, e, t, n, r);
        }
        return n[o].exports;
    }
    var i = typeof require == "function" && require;
    for (var o = 0; o < r.length; o++)
        s(r[o]);
    return s;
})({
    1: [function(require, module, exports) {
        var process = module.exports = {};
        process.nextTick = function() {
            var canSetImmediate = typeof window !== "undefined" && window.setImmediate;
            var canPost = typeof window !== "undefined" && window.postMessage && window.addEventListener;
            if (canSetImmediate) {
                return function(f) {
                    return window.setImmediate(f);
                }
                ;
            }
            if (canPost) {
                var queue = [];
                window.addEventListener("message", function(ev) {
                    var source = ev.source;
                    if ((source === window || source === null) && ev.data === "process-tick") {
                        ev.stopPropagation();
                        if (queue.length > 0) {
                            var fn = queue.shift();
                            fn();
                        }
                    }
                }, true);
                return function nextTick(fn) {
                    queue.push(fn);
                    window.postMessage("process-tick", "*");
                }
                ;
            }
            return function nextTick(fn) {
                setTimeout(fn, 0);
            }
            ;
        }();
        process.title = "browser";
        process.browser = true;
        process.env = {};
        process.argv = [];
        function noop() {}
        process.on = noop;
        process.addListener = noop;
        process.once = noop;
        process.off = noop;
        process.removeListener = noop;
        process.removeAllListeners = noop;
        process.emit = noop;
        process.binding = function(name) {
            throw new Error("process.binding is not supported");
        }
        ;
        process.cwd = function() {
            return "/";
        }
        ;
        process.chdir = function(dir) {
            throw new Error("process.chdir is not supported");
        }
        ;
    }
    , {}],
    2: [function(require, module, exports) {
        "use strict";
        var asap = require("asap");
        module.exports = Promise;
        function Promise(fn) {
            if (typeof this !== "object")
                throw new TypeError("Promises must be constructed via new");
            if (typeof fn !== "function")
                throw new TypeError("not a function");
            var state = null;
            var value = null;
            var deferreds = [];
            var self = this;
            this.then = function(onFulfilled, onRejected) {
                return new self.constructor(function(resolve, reject) {
                    handle(new Handler(onFulfilled,onRejected,resolve,reject));
                }
                );
            }
            ;
            function handle(deferred) {
                if (state === null) {
                    deferreds.push(deferred);
                    return;
                }
                asap(function() {
                    var cb = state ? deferred.onFulfilled : deferred.onRejected;
                    if (cb === null) {
                        (state ? deferred.resolve : deferred.reject)(value);
                        return;
                    }
                    var ret;
                    try {
                        ret = cb(value);
                    } catch (e) {
                        deferred.reject(e);
                        return;
                    }
                    deferred.resolve(ret);
                });
            }
            function resolve(newValue) {
                try {
                    if (newValue === self)
                        throw new TypeError("A promise cannot be resolved with itself.");
                    if (newValue && (typeof newValue === "object" || typeof newValue === "function")) {
                        var then = newValue.then;
                        if (typeof then === "function") {
                            doResolve(then.bind(newValue), resolve, reject);
                            return;
                        }
                    }
                    state = true;
                    value = newValue;
                    finale();
                } catch (e) {
                    reject(e);
                }
            }
            function reject(newValue) {
                state = false;
                value = newValue;
                finale();
            }
            function finale() {
                for (var i = 0, len = deferreds.length; i < len; i++)
                    handle(deferreds[i]);
                deferreds = null;
            }
            doResolve(fn, resolve, reject);
        }
        function Handler(onFulfilled, onRejected, resolve, reject) {
            this.onFulfilled = typeof onFulfilled === "function" ? onFulfilled : null;
            this.onRejected = typeof onRejected === "function" ? onRejected : null;
            this.resolve = resolve;
            this.reject = reject;
        }
        function doResolve(fn, onFulfilled, onRejected) {
            var done = false;
            try {
                fn(function(value) {
                    if (done)
                        return;
                    done = true;
                    onFulfilled(value);
                }, function(reason) {
                    if (done)
                        return;
                    done = true;
                    onRejected(reason);
                });
            } catch (ex) {
                if (done)
                    return;
                done = true;
                onRejected(ex);
            }
        }
    }
    , {
        asap: 4
    }],
    3: [function(require, module, exports) {
        "use strict";
        var Promise = require("./core.js");
        var asap = require("asap");
        module.exports = Promise;
        function ValuePromise(value) {
            this.then = function(onFulfilled) {
                if (typeof onFulfilled !== "function")
                    return this;
                return new Promise(function(resolve, reject) {
                    asap(function() {
                        try {
                            resolve(onFulfilled(value));
                        } catch (ex) {
                            reject(ex);
                        }
                    });
                }
                );
            }
            ;
        }
        ValuePromise.prototype = Promise.prototype;
        var TRUE = new ValuePromise(true);
        var FALSE = new ValuePromise(false);
        var NULL = new ValuePromise(null);
        var UNDEFINED = new ValuePromise(undefined);
        var ZERO = new ValuePromise(0);
        var EMPTYSTRING = new ValuePromise("");
        Promise.resolve = function(value) {
            if (value instanceof Promise)
                return value;
            if (value === null)
                return NULL;
            if (value === undefined)
                return UNDEFINED;
            if (value === true)
                return TRUE;
            if (value === false)
                return FALSE;
            if (value === 0)
                return ZERO;
            if (value === "")
                return EMPTYSTRING;
            if (typeof value === "object" || typeof value === "function") {
                try {
                    var then = value.then;
                    if (typeof then === "function") {
                        return new Promise(then.bind(value));
                    }
                } catch (ex) {
                    return new Promise(function(resolve, reject) {
                        reject(ex);
                    }
                    );
                }
            }
            return new ValuePromise(value);
        }
        ;
        Promise.all = function(arr) {
            var args = Array.prototype.slice.call(arr);
            return new Promise(function(resolve, reject) {
                if (args.length === 0)
                    return resolve([]);
                var remaining = args.length;
                function res(i, val) {
                    try {
                        if (val && (typeof val === "object" || typeof val === "function")) {
                            var then = val.then;
                            if (typeof then === "function") {
                                then.call(val, function(val) {
                                    res(i, val);
                                }, reject);
                                return;
                            }
                        }
                        args[i] = val;
                        if (--remaining === 0) {
                            resolve(args);
                        }
                    } catch (ex) {
                        reject(ex);
                    }
                }
                for (var i = 0; i < args.length; i++) {
                    res(i, args[i]);
                }
            }
            );
        }
        ;
        Promise.reject = function(value) {
            return new Promise(function(resolve, reject) {
                reject(value);
            }
            );
        }
        ;
        Promise.race = function(values) {
            return new Promise(function(resolve, reject) {
                values.forEach(function(value) {
                    Promise.resolve(value).then(resolve, reject);
                });
            }
            );
        }
        ;
        Promise.prototype["catch"] = function(onRejected) {
            return this.then(null, onRejected);
        }
        ;
    }
    , {
        "./core.js": 2,
        asap: 4
    }],
    4: [function(require, module, exports) {
        (function(process) {
            var head = {
                task: void 0,
                next: null
            };
            var tail = head;
            var flushing = false;
            var requestFlush = void 0;
            var isNodeJS = false;
            function flush() {
                while (head.next) {
                    head = head.next;
                    var task = head.task;
                    head.task = void 0;
                    var domain = head.domain;
                    if (domain) {
                        head.domain = void 0;
                        domain.enter();
                    }
                    try {
                        task();
                    } catch (e) {
                        if (isNodeJS) {
                            if (domain) {
                                domain.exit();
                            }
                            setTimeout(flush, 0);
                            if (domain) {
                                domain.enter();
                            }
                            throw e;
                        } else {
                            setTimeout(function() {
                                throw e;
                            }, 0);
                        }
                    }
                    if (domain) {
                        domain.exit();
                    }
                }
                flushing = false;
            }
            if (typeof process !== "undefined" && process.nextTick) {
                isNodeJS = true;
                requestFlush = function() {
                    process.nextTick(flush);
                }
                ;
            } else if (typeof setImmediate === "function") {
                if (typeof window !== "undefined") {
                    requestFlush = setImmediate.bind(window, flush);
                } else {
                    requestFlush = function() {
                        setImmediate(flush);
                    }
                    ;
                }
            } else if (typeof MessageChannel !== "undefined") {
                var channel = new MessageChannel();
                channel.port1.onmessage = flush;
                requestFlush = function() {
                    channel.port2.postMessage(0);
                }
                ;
            } else {
                requestFlush = function() {
                    setTimeout(flush, 0);
                }
                ;
            }
            function asap(task) {
                tail = tail.next = {
                    task: task,
                    domain: isNodeJS && process.domain,
                    next: null
                };
                if (!flushing) {
                    flushing = true;
                    requestFlush();
                }
            }
            module.exports = asap;
        }
        ).call(this, require("_process"));
    }
    , {
        _process: 1
    }],
    5: [function(require, module, exports) {
        if (typeof Promise.prototype.done !== "function") {
            Promise.prototype.done = function(onFulfilled, onRejected) {
                var self = arguments.length ? this.then.apply(this, arguments) : this;
                self.then(null, function(err) {
                    setTimeout(function() {
                        throw err;
                    }, 0);
                });
            }
            ;
        }
    }
    , {}],
    6: [function(require, module, exports) {
        var asap = require("asap");
        if (typeof Promise === "undefined") {
            Promise = require("./lib/core.js");
            require("./lib/es6-extensions.js");
        }
        require("./polyfill-done.js");
    }
    , {
        "./lib/core.js": 2,
        "./lib/es6-extensions.js": 3,
        "./polyfill-done.js": 5,
        asap: 4
    }]
}, {}, [6]);
(function(win, lib) {
    var Promise = win.Promise;
    var ready = Promise.resolve();
    //检查缓存
    var localStorage = win.localStorage;
    if (!!localStorage) {
        try {
            localStorage.setItem('@private', 'false');
        } catch (e) {
            localStorage = false;
        }
    }
    // utitlites
    function defer() {
        var deferred = {};
        var promise = new Promise(function(resolve, reject) {
            deferred.resolve = resolve;
            deferred.reject = reject;
        }
        );
        deferred.promise = promise;
        return deferred;
    }
    function defaults(params, defaultParams) {
        for (var key in defaultParams) {
            if (params[key] === undefined) {
                params[key] = defaultParams[key];
            }
        }
        return params;
    }
    function appendScript(script) {
        var el = document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0] || document.firstElementChild || document;
        el.appendChild(script);
    }
    function stringifyQS(qs) {
        var str = [];
        for (var key in qs) {
            if (!!qs[key]) {
                str.push(key + '=' + encodeURIComponent(qs[key]));
            }
        }
        return str.join('&');
    }
    function md5(string) {
        function rotateLeft(lValue, iShiftBits) {
            return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
        }
        function addUnsigned(lX, lY) {
            var lX4, lY4, lX8, lY8, lResult;
            lX8 = (lX & 0x80000000);
            lY8 = (lY & 0x80000000);
            lX4 = (lX & 0x40000000);
            lY4 = (lY & 0x40000000);
            lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
            if (lX4 & lY4) {
                return ( lResult ^ 0x80000000 ^ lX8 ^ lY8) ;
            }
            if (lX4 | lY4) {
                if (lResult & 0x40000000) {
                    return ( lResult ^ 0xC0000000 ^ lX8 ^ lY8) ;
                } else {
                    return ( lResult ^ 0x40000000 ^ lX8 ^ lY8) ;
                }
            } else {
                return ( lResult ^ lX8 ^ lY8) ;
            }
        }
        function f(x, y, z) {
            return (x & y) | ((~x) & z);
        }
        function g(x, y, z) {
            return (x & z) | (y & (~z));
        }
        function h(x, y, z) {
            return ( x ^ y ^ z) ;
        }
        function i(x, y, z) {
            return ( y ^ (x | (~z))) ;
        }
        function FF(a, b, c, d, x, s, ac) {
            a = addUnsigned(a, addUnsigned(addUnsigned(f(b, c, d), x), ac));
            return addUnsigned(rotateLeft(a, s), b);
        }
        function GG(a, b, c, d, x, s, ac) {
            a = addUnsigned(a, addUnsigned(addUnsigned(g(b, c, d), x), ac));
            return addUnsigned(rotateLeft(a, s), b);
        }
        function HH(a, b, c, d, x, s, ac) {
            a = addUnsigned(a, addUnsigned(addUnsigned(h(b, c, d), x), ac));
            return addUnsigned(rotateLeft(a, s), b);
        }
        function II(a, b, c, d, x, s, ac) {
            a = addUnsigned(a, addUnsigned(addUnsigned(i(b, c, d), x), ac));
            return addUnsigned(rotateLeft(a, s), b);
        }
        function convertToWordArray(string) {
            var lWordCount;
            var lMessageLength = string.length;
            var lNumberOfWords_temp1 = lMessageLength + 8;
            var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64;
            var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
            var lWordArray = new Array(lNumberOfWords - 1);
            var lBytePosition = 0;
            var lByteCount = 0;
            while (lByteCount < lMessageLength) {
                lWordCount = (lByteCount - (lByteCount % 4)) / 4;
                lBytePosition = (lByteCount % 4) * 8;
                lWordArray[lWordCount] = (lWordArray[lWordCount] | (string.charCodeAt(lByteCount) << lBytePosition));
                lByteCount++;
            }
            lWordCount = (lByteCount - (lByteCount % 4)) / 4;
            lBytePosition = (lByteCount % 4) * 8;
            lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
            lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
            lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
            return lWordArray;
        }
        function wordToHex(lValue) {
            var WordToHexValue = "", WordToHexValue_temp = "", lByte, lCount;
            for (lCount = 0; lCount <= 3; lCount++) {
                lByte = (lValue >>> (lCount * 8)) & 255;
                WordToHexValue_temp = "0" + lByte.toString(16);
                WordToHexValue = WordToHexValue + WordToHexValue_temp.substr(WordToHexValue_temp.length - 2, 2);
            }
            return WordToHexValue;
        }
        function utf8Encode(string) {
            string = string.replace(/\r\n/g, "\n");
            var utftext = "";
            for (var n = 0; n < string.length; n++) {
                var c = string.charCodeAt(n);
                if (c < 128) {
                    utftext += String.fromCharCode(c);
                } else if ((c > 127) && (c < 2048)) {
                    utftext += String.fromCharCode((c >> 6) | 192);
                    utftext += String.fromCharCode((c & 63) | 128);
                } else {
                    utftext += String.fromCharCode((c >> 12) | 224);
                    utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                    utftext += String.fromCharCode((c & 63) | 128);
                }
            }
            return utftext;
        }
        var x = [], k, AA, BB, CC, DD, a, b, c, d, S11 = 7, S12 = 12, S13 = 17, S14 = 22, S21 = 5, S22 = 9, S23 = 14, S24 = 20, S31 = 4, S32 = 11, S33 = 16, S34 = 23, S41 = 6, S42 = 10, S43 = 15, S44 = 21;
        string = utf8Encode(string);
        x = convertToWordArray(string);
        a = 0x67452301;
        b = 0xEFCDAB89;
        c = 0x98BADCFE;
        d = 0x10325476;
        for (k = 0; k < x.length; k += 16) {
            AA = a;
            BB = b;
            CC = c;
            DD = d;
            a = FF(a, b, c, d, x[k + 0], S11, 0xD76AA478);
            d = FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);
            c = FF(c, d, a, b, x[k + 2], S13, 0x242070DB);
            b = FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);
            a = FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF);
            d = FF(d, a, b, c, x[k + 5], S12, 0x4787C62A);
            c = FF(c, d, a, b, x[k + 6], S13, 0xA8304613);
            b = FF(b, c, d, a, x[k + 7], S14, 0xFD469501);
            a = FF(a, b, c, d, x[k + 8], S11, 0x698098D8);
            d = FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF);
            c = FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1);
            b = FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE);
            a = FF(a, b, c, d, x[k + 12], S11, 0x6B901122);
            d = FF(d, a, b, c, x[k + 13], S12, 0xFD987193);
            c = FF(c, d, a, b, x[k + 14], S13, 0xA679438E);
            b = FF(b, c, d, a, x[k + 15], S14, 0x49B40821);
            a = GG(a, b, c, d, x[k + 1], S21, 0xF61E2562);
            d = GG(d, a, b, c, x[k + 6], S22, 0xC040B340);
            c = GG(c, d, a, b, x[k + 11], S23, 0x265E5A51);
            b = GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA);
            a = GG(a, b, c, d, x[k + 5], S21, 0xD62F105D);
            d = GG(d, a, b, c, x[k + 10], S22, 0x2441453);
            c = GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681);
            b = GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8);
            a = GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6);
            d = GG(d, a, b, c, x[k + 14], S22, 0xC33707D6);
            c = GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87);
            b = GG(b, c, d, a, x[k + 8], S24, 0x455A14ED);
            a = GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905);
            d = GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8);
            c = GG(c, d, a, b, x[k + 7], S23, 0x676F02D9);
            b = GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A);
            a = HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942);
            d = HH(d, a, b, c, x[k + 8], S32, 0x8771F681);
            c = HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122);
            b = HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C);
            a = HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44);
            d = HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9);
            c = HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60);
            b = HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70);
            a = HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6);
            d = HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA);
            c = HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085);
            b = HH(b, c, d, a, x[k + 6], S34, 0x4881D05);
            a = HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039);
            d = HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5);
            c = HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8);
            b = HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665);
            a = II(a, b, c, d, x[k + 0], S41, 0xF4292244);
            d = II(d, a, b, c, x[k + 7], S42, 0x432AFF97);
            c = II(c, d, a, b, x[k + 14], S43, 0xAB9423A7);
            b = II(b, c, d, a, x[k + 5], S44, 0xFC93A039);
            a = II(a, b, c, d, x[k + 12], S41, 0x655B59C3);
            d = II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92);
            c = II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D);
            b = II(b, c, d, a, x[k + 1], S44, 0x85845DD1);
            a = II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F);
            d = II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0);
            c = II(c, d, a, b, x[k + 6], S43, 0xA3014314);
            b = II(b, c, d, a, x[k + 13], S44, 0x4E0811A1);
            a = II(a, b, c, d, x[k + 4], S41, 0xF7537E82);
            d = II(d, a, b, c, x[k + 11], S42, 0xBD3AF235);
            c = II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB);
            b = II(b, c, d, a, x[k + 9], S44, 0xEB86D391);
            a = addUnsigned(a, AA);
            b = addUnsigned(b, BB);
            c = addUnsigned(c, CC);
            d = addUnsigned(d, DD);
        }
        var temp = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d);
        return temp.toLowerCase();
    }
    function readCookie(name) {
        var matched = new RegExp('(?:^|;\\s*)' + name + '\\=([^;]+)(?:;\\s*|$)').exec(document.cookie);
        if (matched) {
            return matched[1];
        }
    }
    function delCookie(name, mainDomain, subDomain) {
        var now = new Date();
        now.setTime(now.getTime() - 86400 * 1000);
        var path = '/';
        doc.cookie = name + '=;path=' + path + ';domain=.' + mainDomain + ';expires=' + now.toGMTString();
        doc.cookie = name + '=;path=' + path + ';domain=.' + subDomain + '.' + mainDomain + ';expires=' + now.toGMTString();
    }
    /**
 * @namespace lib
 */
    /**
 * @namespace mtop
 * @memberOf lib
 */
    /**
 * @member config
 * @memberof lib.mtop
 * @property {String} prefix mtop请求地址前缀
 * @property {String} mainDomain mtop请求地址主域，例如：taobao.com/tmall.com
 * @property {String} subDomain mtop请求地址主域，例如：m/wapa/waptest
 */
    var globalConfig = {
        useAlipayJSBridge: false // 默认不使用支付宝的JSBridge获得token
    };
    var middlewares = [];
    /**
 * @enum {Object}
 * @readonly
 * @memberof lib.mtop
 */
    var RESPONSE_TYPE = {
        /**
     * @description 请求出错
     * @type {Number}
     */
        'ERROR': -1,
        /**
     * @description 请求成功
     * @type {Number}
     */
        'SUCCESS': 0,
        /**
     * @description 请求token过期
     * @type {Number}
     */
        'TOKEN_EXPIRED': 1,
        /**
     * @description 请求session过期
     * @type {Number}
     */
        'SESSION_EXPIRED': 2
    };
    function parseDomainEnv() {
        var hostname = win.location.hostname;
        var hosts = ['taobao.net', 'taobao.com', 'tmall.com', 'tmall.hk', 'etao.com', 'alibaba.com', 'alibaba-inc.com', 'alipay.com', 'aliyun.com', 'tdd.la'];
        var regexp = new RegExp('([^.]*?)\\.?((?:' + hosts.join(')|(?:').replace(/\./g, '\\.') + '))','i');
        var matched = hostname.match(regexp) || [];
        var mainDomain = matched[2] || 'taobao.com';
        var subDomain = matched[1] || 'm';
        if (mainDomain === 'taobao.net' && (subDomain === 'x' || subDomain === 'waptest' || subDomain === 'daily')) {
            subDomain = 'waptest';
        } else if (mainDomain === 'taobao.net' && subDomain === 'demo') {
            subDomain = 'demo';
        } else if (mainDomain === 'taobao.com' && subDomain === 'tms') {
            subDomain = 'm';
        } else if (mainDomain === 'tmall.com' && subDomain === 'www') {
            subDomain = 'm';
        } else if (mainDomain === 'tdd.la' && subDomain === 'm') {
            subDomain = '';
        }
        var prefix = mainDomain === 'etao.com' ? 'apie' : 'api';
        globalConfig.mainDomain = mainDomain;
        globalConfig.subDomain = subDomain;
        globalConfig.prefix = prefix;
    }
    parseDomainEnv();
    function parseNativeEnv() {
        var ua = win.navigator.userAgent;
        var WindVaneVersion = ua.match(/WindVane[\/\s]([\d\.\_]+)/);
        if (WindVaneVersion) {
            globalConfig.WindVaneVersion = WindVaneVersion[1];
        }
        var AliApp = ua.match(/AliApp\(([^\/]+)\/([\d\.\_]+)\)/i);
        if (AliApp) {
            globalConfig.AliAppName = AliApp[1];
            globalConfig.AliAppVersion = AliApp[2];
        }
    }
    parseNativeEnv();
    /**
 * @typedef {Object} requestParams
 * @property {String} api - 请求api的名称
 * @property {Object} data - 请求api的数据
 * @property {String} v - 请求api的版本
 * @property {String} [type=GET] - 请求的类型，GET/POST
 * @property {String} [dataType=jsonp] - 请求的数据格式，jsonp/json
 * @property {String} [ua] - 人机交互加密串
 * @property {Number} ecode - 签名设置（0-普通签名，1-安全签名）
 * @property {String} [timeout=20000] - 请求的超时时间
 */
    var mtopInc = 0;
    /**
 * Mtop类
 * @class lib.mtop~Mtop
 * @param {requestParams} params 请求参数
 */
    function Mtop(params) {
        this.id = (++mtopInc);
        this.params = defaults(params || {}, {
            v: '*',
            data: {},
            type: 'get',
            dataType: 'jsonp'
        });
        this.params.type = this.params.type.toLowerCase();
        if (typeof this.params.data === 'object') {
            this.params.data = JSON.stringify(this.params.data);
        }
        this.middlewares = middlewares.slice(0);
    }
    Mtop.prototype.use = function(middleware) {
        if (!middleware) {
            throw new Error('middleware is undefined');
        }
        this.middlewares.push(middleware);
        return this;
    }
    ;
    Mtop.prototype.__processRequestMethod = function(next) {
        var params = this.params;
        var options = this.options;
        if (params.type === 'get' && params.dataType === 'jsonp') {
            options.getJSONP = true;
        } else if (params.type === 'get' && params.dataType === 'json') {
            options.getJSON = true;
        } else if (params.type === 'post') {
            options.postJSON = true;
        }
        next();
    }
    ;
    Mtop.prototype.__processRequestType = function(next) {
        var that = this;
        var options = this.options;
        if (globalConfig.H5Request === true) {
            // 全局设置优先
            options.H5Request = true;
        }
        if (globalConfig.WindVaneRequest === true) {
            // 全局设置优先
            options.WindVaneRequest = true;
        }
        // 判断H5请求还是Native请求的逻辑
        if (options.H5Request === false && options.WindVaneRequest === true) {
            // 强制发起Native请求
            if (!lib.windvane || parseFloat(options.WindVaneVersion) < 5.4) {
                throw new Error('WINDVANE_NOT_FOUND::缺少WindVane环境');
            }
        } else if (options.H5Request === true) {
            // 只要H5Rquest为true，则强制发起H5请求
            options.WindVaneRequest = false;
        } else if (typeof options.WindVaneRequest === 'undefined' && typeof options.H5Request === 'undefined') {
            // 如果没有设置，则自动判断
            if (lib.windvane && parseFloat(options.WindVaneVersion) >= 5.4) {
                // 发起Native请求
                options.WindVaneRequest = true;
            } else {
                // 发起H5请求
                options.H5Request = true;
            }
        }
        next().then(function() {
            var ret = options.retJson.ret;
            if (ret instanceof Array) {
                ret = ret.join(',');
            }
            if (options.WindVaneRequest === true && (!ret || ret.indexOf('HY_FAILED') > -1 || ret.indexOf('HY_NO_HANDLER') > -1 || ret.indexOf('HY_CLOSED') > -1 || ret.indexOf('HY_EXCEPTION') > -1 || ret.indexOf('HY_NO_PERMISSION') > -1)) {
                globalConfig.H5Request = true;
                // TODO retry
                return that.__sequence([that.__processRequestType, that.__processToken, that.__processRequestUrl, that.__processUnitPrefix, that.middlewares, that.__processRequest]);
            }
        });
    }
    ;
    var TOKEN_KEY = '_m_h5_tk';
    var TOKEN_ENC_KEY = '_m_h5_tk_enc';
    Mtop.prototype.__getTokenFromAlipay = function() {
        var deferred = defer();
        var options = this.options;
        var ua = win.navigator.userAgent;
        var isOnline = !!location.protocol.match(/^https?\:$/);
        var isAlipay = options.AliAppName === 'AP' && parseFloat(options.AliAppVersion) >= 8.2;
        if (options.useAlipayJSBridge === true && !isOnline && isAlipay && win.AlipayJSBridge && win.AlipayJSBridge.call) {
            // 支付宝客户端（8.2以上），需要调用客户端提供的js来获得.taobao.com域下的cookie
            win.AlipayJSBridge.call('getMtopToken', function(json) {
                if (json && json.token) {
                    options.token = json.token;
                }
                deferred.resolve();
            }, function() {
                deferred.resolve();
            });
        } else {
            deferred.resolve();
        }
        return deferred.promise;
    }
    ;
    Mtop.prototype.__getTokenFromCookie = function() {
        var options = this.options;
        options.token = options.token || readCookie(TOKEN_KEY);
        if (options.token) {
            options.token = options.token.split('_')[0];
        }
        return Promise.resolve();
    }
    ;
    Mtop.prototype.__processToken = function(next) {
        var that = this;
        var options = this.options;
        var params = this.params;
        if (options.token) {
            delete options.token;
        }
        if (options.WindVaneRequest === true) {
            next();
        } else {
            return ready.then(function() {
                return that.__getTokenFromAlipay();
            }).then(function() {
                return that.__getTokenFromCookie();
            }).then(next).then(function() {
                var retJson = options.retJson;
                var ret = retJson.ret;
                if (ret instanceof Array) {
                    ret = ret.join(',');
                }
                if (ret.indexOf('TOKEN_EMPTY') > -1 || ret.indexOf('TOKEN_EXOIRED') > -1) {
                    options.maxRetryTimes = options.maxRetryTimes || 5;
                    options.failTimes = options.failTimes || 0;
                    if (options.H5Request && (++options.failTimes) < options.maxRetryTimes) {
                        // TODO retry
                        return that.__sequence([that.__processToken, that.__processRequestUrl, that.__processUnitPrefix, that.middlewares, that.__processRequest]);
                    } else {
                        if (maxRetryTimes > 0) {
                            delCookie(TOKEN_KEY, options.mainDomain, options.subDomain);
                            delCookie(TOKEN_ENC_KEY, options.mainDomain, options.subDomain);
                        }
                        retJson.retType = RESPONSE_TYPE.TOKEN_EXPIRED;
                    }
                }
            });
        }
    }
    ;
    Mtop.prototype.__processRequestUrl = function(next) {
        var params = this.params;
        var options = this.options;
        if (options.H5Request === true) {
            var path = '//' + (options.prefix ? options.prefix + '.' : '') + (options.subDomain ? options.subDomain + '.' : '') + options.mainDomain + '/h5/' + params.api.toLowerCase() + '/' + params.v.toLowerCase() + '/';
            var timestamp = new Date().getTime();
            var appKey = options.subDomain === 'waptest' ? '4272' : '12574478';
            var sign = md5(options.token + '&' + timestamp + "&" + appKey + "&" + params.data);
            var querystring = {
                appKey: appKey,
                t: timestamp,
                sign: sign
            };
            var postdata = {
                data: params.data,
                ua: params.ua
            };
            Object.keys(params).forEach(function(n) {
                if (typeof querystring[n] === 'undefined' && typeof postdata[n] === 'undefined') {
                    querystring[n] = params[n];
                }
            });
            if (options.getJSONP) {
                querystring.type = 'jsonp';
            } else if (options.getJSON || options.postJSON) {
                querystring.type = 'originaljson';
            }
            options.querystring = querystring;
            options.postdata = postdata;
            options.path = path;
        }
        next();
    }
    ;
    Mtop.prototype.__processUnitPrefix = function(next) {
        var params = this.params;
        var options = this.options;
        if (localStorage && options.H5Request === true) {
            var api = params.api;
            var unitPrefix = false;
            var unitCookie = readCookie('_m_user_unitinfo_');
            var unitStorage = localStorage.getItem('unitinfo');
            //支持缓存 && 存在cookie && cookie字段是单元化 && 存在缓存数组 && 数组有此api
            if (unitCookie && unitCookie.split('|')[0].indexOf('center') < 0 && unitStorage && unitStorage.indexOf(api.toLowerCase()) >= 0) {
                unitPrefix = unitCookie.split('|')[1];
            }
            if (unitPrefix && options.path) {
                options.path = options.path.replace(/^\/\//, '//' + unitPrefix + '.');
            }
            next().then(function() {
                if (localStorage) {
                    var unitCookie = readCookie('_m_unitapi_v_');
                    var unitStorage = localStorage.getItem('unitinfo');
                    if (unitCookie) {
                        var unitinfo = unitStorage ? JSON.parse(unitStorage) : {};
                        //没有缓存数据 或者 版本不一致 拉取数据 jsonp
                        if (!unitStorage || unitCookie !== unitinfo.version) {
                            var isFinish = false;
                            var url = '//h5.' + options.subDomain + '.taobao.com/js/mtop/unit/' + unitCookie + '/unitApi.js';
                            var script = document.createElement('script');
                            script.src = url;
                            var finish = function() {
                                if (isFinish)
                                    return;
                                isFinish = true;
                                script.onload = script.onerror = null;
                                if (script.parentNode) {
                                    script.parentNode.removeChild(script);
                                }
                            };
                            script.onerror = function() {
                                finish();
                            }
                            ;
                            //jsonp 方法
                            if (!win.jsonp_unitapi) {
                                win.jsonp_unitapi = function(json) {
                                    finish();
                                    localStorage.setItem('unitinfo', JSON.stringify(json));
                                }
                                ;
                            }
                            appendScript(script);
                        }
                    }
                }
            });
        } else {
            next();
        }
    }
    ;
    var jsonpInc = 0;
    Mtop.prototype.__requestJSONP = function(throwError) {
        var deferred = defer();
        var params = this.params;
        var options = this.options;
        function cleanup(type) {
            if (timeoutid) {
                clearTimeout(timeoutid);
            }
            if (script.parentNode) {
                script.parentNode.removeChild(script);
            }
            if (type === 'TIMEOUT') {
                window[callbackName] = function() {
                    window[callbackName] = undef;
                    try {
                        delete window[callbackName];
                    } catch (e) {}
                }
                ;
            } else {
                window[callbackName] = undefined;
                try {
                    delete window[callbackName];
                } catch (e) {}
            }
        }
        var timeout = params.timeout || 20000;
        var callbackName = 'mtopjsonp' + (++jsonpInc);
        var timeoutid = setTimeout(function() {
            cleanup('TIMEOUT');
            throwError('TIMEOUT::接口超时');
        }, timeout);
        options.querystring.callback = callbackName;
        var script = document.createElement('script');
        script.src = options.path + '?' + stringifyQS(options.querystring) + '&' + stringifyQS(options.postdata);
        script.sync = true;
        script.onerror = function() {
            cleanup('ABORT');
            throwError('ABORT::接口异常退出');
        }
        ;
        window[callbackName] = function() {
            options.results = Array.prototype.slice.call(arguments);
            cleanup();
            deferred.resolve();
        }
        ;
        appendScript(script);
        return deferred.promise;
    }
    ;
    Mtop.prototype.__requestJSON = function(throwError) {
        var deferred = defer();
        var params = this.params;
        var options = this.options;
        var xhr = new win.XMLHttpRequest();
        function cleanup(type) {
            if (timeoutid) {
                clearTimeout(timeoutid);
            }
            if (type === 'TIMEOUT') {
                xhr.abort();
            }
        }
        var timeout = params.timeout || 20000;
        var timeoutid = setTimeout(function() {
            cleanup('TIMEOUT');
            throwError('TIMEOUT::接口超时');
        }, timeout);
        xhr.onreadystatechange = function() {
            if (xhr.readyState == 4) {
                var status = xhr.status;
                var result;
                var headers;
                if ((status >= 200 && status < 300) || status == 304) {
                    cleanup();
                    result = xhr.responseText;
                    headers = xhr.getAllResponseHeaders() || '';
                    try {
                        result = (/^\s*$/).test(result) ? {} : JSON.parse(result);
                        result.responseHeaders = headers;
                        options.results = [result];
                        deferred.resolve();
                    } catch (e) {
                        throwError('PARSE_JSON_ERROR::解析JSON失败');
                    }
                } else {
                    cleanup('ABORT');
                    throwError('ABORT::接口异常退出');
                }
            }
        }
        ;
        var curl = options.path + '?' + stringifyQS(options.querystring);
        var type;
        var senddata;
        if (options.getJSON) {
            type = 'GET';
            curl += '&' + stringifyQS(options.postdata);
        } else if (options.postJSON) {
            type = 'POST';
            senddata = stringifyQS(options.postdata);
        }
        xhr.open(type, curl, true);
        xhr.withCredentials = true;
        xhr.setRequestHeader('Accept', 'application/json');
        xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
        if (params.headers) {
            for (var key in params.headers) {
                xhr.setRequestHeader(key, params.headers[key]);
            }
        }
        xhr.send(senddata);
        return deferred.promise;
    }
    ;
    Mtop.prototype.__requestWindVane = function(throwError) {
        var deferred = defer();
        var params = this.params;
        var options = this.options;
        var data = params.data;
        var api = params.api;
        var v = params.v;
        var post = !!options.postJSON ? 1 : 0;
        var type = (!!options.getJSON || !!options.postJSON) ? 'orginaljson' : '';
        var isHttps = location.protocol === 'https' ? 1 : 0;
        var isSec = params.isSec || 0;
        var sessionOption = params.sessionOption || 'AutoLoginOnly';
        var ecode;
        var timeout;
        var timer;
        if (typeof params.ecode === 'undefined') {
            throw new Error('UNEXCEPT_PARAM_ECODE::缺少ecode参数');
        } else {
            ecode = parseInt(params.ecode);
        }
        if (typeof params.timer !== 'undefined') {
            timer = parseInt(params.timer);
        } else if (typeof params.timeout !== 'undefined') {
            timer = parseInt(params.timeout);
        } else {
            timer = 20000;
        }
        timeout = timer * 2;
        function handler(result) {
            options.results = [result];
            deferred.resolve();
        }
        lib.windvane.call('MtopWVPlugin', 'send', {
            api: api,
            v: v,
            post: String(post),
            type: type,
            isHttps: String(isHttps),
            ecode: String(ecode),
            isSec: String(isSec),
            param: JSON.parse(data),
            timer: timer,
            sessionOption: sessionOption
        }, handler, handler, timeout);
        return deferred.promise;
    }
    ;
    Mtop.prototype.__processRequest = function(next, throwError) {
        var that = this;
        return ready.then(function() {
            var options = that.options;
            if (!!options.H5Request && !!options.getJSONP) {
                return that.__requestJSONP(throwError);
            } else if (!!options.H5Request && (!!options.getJSON || !!options.postJSON)) {
                return that.__requestJSON(throwError);
            } else if (!!options.WindVaneRequest) {
                return that.__requestWindVane(throwError);
            } else {
                throw new Error('UNEXCEPT_REQUEST::错误的请求类型');
            }
        }).then(next).then(function() {
            var options = that.options;
            var params = that.params;
            var retJson = options.results[0];
            var ret = (retJson && retJson.ret || []);
            retJson.ret = ret;
            if (ret instanceof Array) {
                ret = ret.join(',');
            }
            if (ret.indexOf('SUCCESS') > -1) {
                retJson.retType = RESPONSE_TYPE.SUCCESS;
            } else {
                retJson.retType = RESPONSE_TYPE.ERROR;
            }
            options.retJson = retJson;
        })
    }
    ;
    Mtop.prototype.__sequence = function(fnArray) {
        var that = this;
        var preProcessor = [];
        var postProcessor = [];
        function add(fn) {
            if (fn instanceof Array) {
                fn.forEach(add);
            } else {
                var pre = defer();
                var post = defer();
                var next;
                preProcessor.push(function() {
                    pre = defer();
                    next = fn.call(that, function(result) {
                        pre.resolve(result);
                        return post.promise;
                    }, function(errMsg) {
                        pre.reject(errMsg);
                        return post.promise;
                    });
                    if (next) {
                        next = next['catch'](function(e) {
                            pre.reject(e);
                        });
                    }
                    return pre.promise;
                });
                postProcessor.push(function(result) {
                    post.resolve(result);
                    return next;
                });
            }
        }
        fnArray.forEach(add);
        var promise = ready;
        var processor;
        while (!!(processor = preProcessor.shift())) {
            promise = promise.then(processor);
        }
        while (!!(processor = postProcessor.pop())) {
            promise = promise.then(processor);
        }
        return promise;
    }
    ;
    var startPoint = function(next) {
        next();
    };
    var endPoint = function(next) {
        next();
    };
    /**
 * 在浏览器中，会通过Ajax方式发起请求（H5）。在手淘和天猫客户端中，会通过客户端原生接口发起请求（MtopPlugin）。
 * @method request
 * @return {Promise}  Promise实例
 * @memberOf Mtop
 * @instance
 */
    Mtop.prototype.request = function(options) {
        var that = this;
        this.options = defaults(options || {}, globalConfig);
        var promise = Promise.resolve([startPoint, endPoint]).then(function(ret) {
            var __processStart = ret[0];
            var __processEnd = ret[1];
            return that.__sequence([__processStart, that.__processRequestMethod, that.__processRequestType, that.__processToken, that.__processRequestUrl, that.__processUnitPrefix, that.middlewares, that.__processRequest, __processEnd]);
        }).then(function() {
            var retJson = that.options.retJson;
            if (retJson.retType !== RESPONSE_TYPE.SUCCESS) {
                return Promise.reject(retJson);
            } else {
                if (that.options.successCallback) {
                    that.options.successCallback(retJson);
                }
                return Promise.resolve(retJson);
            }
        })['catch'](function(reason) {
            var retJson;
            if (reason instanceof Error) {
                console.error(reason.stack);
                retJson = {
                    ret: [reason.message],
                    stack: [reason.stack],
                    retJson: RESPONSE_TYPE.ERROR
                };
            } else if (typeof reason === 'string') {
                retJson = {
                    ret: [reason],
                    retJson: RESPONSE_TYPE.ERROR
                };
            } else if (reason !== undefined) {
                retJson = reason;
            } else {
                retJson = that.options.retJson;
            }
            if (that.options.failureCallback) {
                that.options.failureCallback(retJson);
            }
            return Promise.reject(retJson);
        });
        startPoint = function(next) {
            promise.then(next)['catch'](next);
        }
        ;
        return promise;
    }
    ;
    lib.mtop = function(params) {
        return new Mtop(params);
    }
    ;
    /**
 * 在浏览器中，会通过Ajax方式发起请求（H5）。在手淘和天猫客户端中，会通过客户端原生接口发起请求（MtopPlugin）。
 * @deprecated 请使用new Mtop(params).request();
 * @method request
 * @param {requestParams} params - 请求参数
 * @param {Function} [successCallback] 成功回调
 * @param {Function} [failureCallback] 失败回调
 * @return {Promise} Promise对象实例
 * @memberof lib.mtop
 */
    lib.mtop.request = function(params, successCallback, failureCallback) {
        var options = {
            H5Request: params.H5Request,
            WindVaneRequest: params.WindVaneRequest,
            LoginRequest: params.LoginRequest,
            AntiCreep: params.AntiCreep,
            AntiFlood: params.AntiFlood,
            successCallback: successCallback,
            failureCallback: failureCallback || successCallback
        };
        return new Mtop(params).request(options);
    }
    ;
    /**
 * 强制发起H5请求
 * @deprecated 请使用new Mtop(params).H5Request();
 * @method H5Request
 * @param  {requestParams} params - 请求参数
 * @param {Function} [successCallback] 成功回调
 * @param {Function} [failureCallback] 失败回调
 * @return {Promise}  Promise实例
 * @memberof lib.mtop
 */
    lib.mtop.H5Request = function(params, successCallback, failureCallback) {
        var options = {
            H5Request: true,
            successCallback: successCallback,
            failureCallback: failureCallback || successCallback
        };
        return new Mtop(params).request(options);
    }
    ;
    lib.mtop.middlewares = middlewares;
    lib.mtop.config = globalConfig;
    lib.mtop.RESPONSE_TYPE = RESPONSE_TYPE;
    lib.mtop.CLASS = Mtop;
})(window, window.lib || (window.lib = {}));
;(function(win, lib) {
    var Promise = win.Promise;
    var Mtop = lib.mtop.CLASS;
    var globalConfig = lib.mtop.config;
    var RESPONSE_TYPE = lib.mtop.RESPONSE_TYPE;
    function preventMove(e) {
        e.preventDefault();
        return false;
    }
    function FrameWidget(text, url) {
        var that = this;
        var dpr = win.dpr || 1;
        var widget = document.createElement('div');
        var rect = document.documentElement.getBoundingClientRect();
        var width = Math.max(rect.width, window.innerWidth) / dpr;
        var height = Math.max(rect.height, window.innerHeight) / dpr;
        widget.style.cssText = ['-webkit-transform:scale(' + dpr + ') translateZ(0)', '-ms-transform:scale(' + dpr + ') translateZ(0)', 'transform:scale(' + dpr + ') translateZ(0)', '-webkit-transform-origin:0 0', '-ms-transform-origin:0 0', 'transform-origin:0 0', 'width:' + width + 'px', 'height:' + height + 'px', 'z-index:999999', 'position:absolute', 'left:0', 'top:0px', 'background:#FFF', 'display:none'].join(';');
        var title = document.createElement('div');
        title.style.cssText = ['width:100%', 'height:' + 52 + 'px', 'background:#EEE', 'line-height:' + 52 + 'px', 'text-align:left', 'box-sizing:border-box', 'padding-left:' + 20 + 'px', 'position:absolute', 'left:0', 'top:0', 'font-size:' + 16 + 'px', 'font-weight:bold', 'color:#333'].join(';');
        title.innerText = text;
        var close = document.createElement('a');
        close.style.cssText = ['display:block', 'position:absolute', 'right:0', 'top:0', 'height:' + 52 + 'px', 'line-height:' + 52 + 'px', 'padding:0 ' + 20 + 'px', 'color:#999'].join(';');
        close.innerText = '关闭';
        var content = document.createElement('iframe');
        content.style.cssText = ['width:100%', 'height:100%', 'border:0', 'overflow:hidden'].join(';');
        title.appendChild(close);
        widget.appendChild(title);
        widget.appendChild(content);
        document.body.appendChild(widget);
        content.src = url;
        close.addEventListener('click', function() {
            that.hide();
            var ev = document.createEvent('HTMLEvents');
            ev.initEvent('close', false, false);
            widget.dispatchEvent(ev);
        }, false);
        this.addEventListener = function() {
            widget.addEventListener.apply(widget, arguments);
        }
        ;
        this.removeEventListener = function() {
            widget.removeEventListener.apply(widget, arguments);
        }
        ;
        this.show = function() {
            document.addEventListener('touchmove', preventMove, false);
            widget.style.display = 'block';
            window.scrollTo(0, 0);
        }
        ;
        this.hide = function() {
            document.removeEventListener('touchmove', preventMove);
            window.scrollTo(0, -rect.top);
            if (widget.parentNode) {
                widget.parentNode.removeChild(widget);
            }
        }
        ;
    }
    function processLoginRequest(next) {
        var that = this;
        var options = this.options;
        var params = this.params;
        // 用WindVane请求的情况下，不需要LoginReuest的插件
        return next().then(function() {
            var retJson = options.retJson;
            var ret = retJson.ret;
            if (ret instanceof Array) {
                ret = ret.join(',');
            }
            if (ret.indexOf('SESSION_EXPIRED') > -1 || ret.indexOf('SID_INVALID') > -1 || ret.indexOf('AUTH_REJECT') > -1 || ret.indexOf('NEED_LOGIN') > -1) {
                retJson.retType = RESPONSE_TYPE.SESSION_EXPIRED;
                if (!options.WindVaneRequest && (globalConfig.LoginRequest === true || options.LoginRequest === true)) {
                    if (!lib.login) {
                        throw new Error('LOGIN_NOT_FOUND::缺少lib.login');
                    }
                    return lib.login.goLoginAsync().then(function(status) {
                        // TODO retry
                        return that.__sequence([that.__processToken, that.__processRequestUrl, that.__processUnitPrefix, that.middlewares, that.__processRequest]);
                    })['catch'](function(status) {
                        if (status === 'CANCEL') {
                            throw new Error('LOGIN_CANCEL::用户取消登录');
                        } else {
                            throw new Error('LOGIN_FAILURE::用户登录失败');
                        }
                    });
                }
            }
        });
    }
    lib.mtop.middlewares.push(processLoginRequest);
    /**
 * 请求Mtop并验证登录
 * @method loginRequest
 * @param {requestParams} params  - 请求参数
 * @param {Function} [successCallback] 成功回调
 * @param {Function} [failureCallback] 失败回调
 * @return {Promise} Promise对象实例
 * @memberof lib.mtop
 */
    lib.mtop.loginRequest = function(params, successCallback, failureCallback) {
        var options = {
            LoginRequest: true,
            H5Request: true,
            successCallback: successCallback,
            failureCallback: failureCallback || successCallback
        };
        return new Mtop(params).request(options);
    }
    ;
    function processAntiFlood(next) {
        var that = this;
        var options = this.options;
        var params = this.params;
        if (!options.AliAppName && !options.AliAppVersion && (globalConfig.AntiFlood === true || options.AntiFlood === true)) {
            return next().then(function() {
                var retJson = options.retJson;
                var ret = retJson.ret;
                if (ret instanceof Array) {
                    ret = ret.join(',');
                }
                if (ret.indexOf('FAIL_SYS_USER_VALIDATE') > -1 && retJson.data.url) {
                    location.href = retJson.data.url;
                }
            });
        } else {
            next();
        }
    }
    /**
 * 请求Mtop并验证防刷
 * @method antiFloodRequest
 * @param {requestParams} params  - 请求参数
 * @param {Function} [successCallback] 成功回调
 * @param {Function} [failureCallback] 失败回调
 * @return {Promise} Promise对象实例
 * @memberof lib.mtop
 */
    lib.mtop.antiFloodRequest = function(params, successCallback, failureCallback) {
        var options = {
            AntiFlood: true,
            successCallback: successCallback,
            failureCallback: failureCallback || successCallback
        };
        return new Mtop(params).request(options);
    }
    ;
    lib.mtop.middlewares.push(processAntiFlood);
    function processAntiCreep(next) {
        var that = this;
        var options = this.options;
        var params = this.params;
        if (!options.AliAppName && !options.AliAppVersion && (globalConfig.AntiCreep === true || options.AntiCreep === true)) {
            return next().then(function() {
                var retJson = options.retJson;
                var ret = retJson.ret;
                if (ret instanceof Array) {
                    ret = ret.join(',');
                }
                if (ret.indexOf('RGV587_ERROR::SM') > -1 && retJson.data.url) {
                    return new Promise(function(resolve, reject) {
                        var url = retJson.data.url;
                        var widget = new FrameWidget('',url);
                        function closeHandler() {
                            widget.removeEventListener('close', closeHandler);
                            win.removeEventListener('message', messageHandler);
                            reject('USER_INPUT_CANCEL::用户取消输入');
                        }
                        function messageHandler(e) {
                            widget.removeEventListener('close', closeHandler);
                            win.removeEventListener('message', messageHandler);
                            widget.hide();
                            var data;
                            try {
                                data = JSON.parse(e.data) || {};
                            } catch (err) {}
                            if (data && data.type === 'child') {
                                var token;
                                try {
                                    token = JSON.parse(decodeURIComponent(data.content));
                                    if (typeof token === 'string') {
                                        token = JSON.parse(token);
                                    }
                                    for (var key in token) {
                                        params[key] = token[key];
                                    }
                                    // TODO retry
                                    that.__sequence([that.__processToken, that.__processRequestUrl, that.__processUnitPrefix, that.middlewares, that.__processRequest]).then(resolve);
                                } catch (err) {
                                    reject('USER_INPUT_FAILURE::用户输入失败');
                                }
                            } else {
                                resolve();
                            }
                        }
                        widget.addEventListener('close', messageHandler, false);
                        win.addEventListener('message', messageHandler, false);
                        widget.show();
                    }
                    );
                }
            });
        } else {
            next();
        }
    }
    /**
 * 请求Mtop并验证防爬
 * @method antiCreepRequest
 * @param {requestParams} params  - 请求参数
 * @param {Function} [successCallback] 成功回调
 * @param {Function} [failureCallback] 失败回调
 * @return {Promise} Promise对象实例
 * @memberof lib.mtop
 */
    lib.mtop.antiCreepRequest = function(params, successCallback, failureCallback) {
        var options = {
            AntiCreep: true,
            successCallback: successCallback,
            failureCallback: failureCallback || successCallback
        };
        return new Mtop(params).request(options);
    }
    ;
    lib.mtop.middlewares.push(processAntiCreep);
})(window, window.lib || (window.lib = {}));
!function(a, b) {
    function c(a) {
        return a.preventDefault(),
        !1
    }
    function d(b, d) {
        var e = this
          , f = a.dpr || 1
          , h = document.createElement("div")
          , i = document.documentElement.getBoundingClientRect()
          , j = Math.max(i.width, window.innerWidth) / f
          , k = Math.max(i.height, window.innerHeight) / f;
        h.style.cssText = ["-webkit-transform:scale(" + f + ") translateZ(0)", "-ms-transform:scale(" + f + ") translateZ(0)", "transform:scale(" + f + ") translateZ(0)", "-webkit-transform-origin:0 0", "-ms-transform-origin:0 0", "transform-origin:0 0", "width:" + j + "px", "height:" + k + "px", "z-index:999999", "position:absolute", "left:0", "top:0px", "background:#FFF", "display:none"].join(";");
        var l = document.createElement("div");
        l.style.cssText = ["width:100%", "height:52px", "background:#EEE", "line-height:52px", "text-align:left", "box-sizing:border-box", "padding-left:20px", "position:absolute", "left:0", "top:0", "font-size:16px", "font-weight:bold", "color:#333"].join(";"),
        l.innerText = b;
        var m = document.createElement("a");
        m.style.cssText = ["display:block", "position:absolute", "right:0", "top:0", "height:52px", "line-height:52px", "padding:0 20px", "color:#999"].join(";"),
        m.innerText = "关闭";
        var n = document.createElement("iframe");
        n.style.cssText = ["width:100%", "height:100%", "border:0", "overflow:hidden"].join(";"),
        l.appendChild(m),
        h.appendChild(l),
        h.appendChild(n),
        g.body.appendChild(h),
        n.src = d,
        m.addEventListener("click", function() {
            e.hide();
            var a = g.createEvent("HTMLEvents");
            a.initEvent("close", !1, !1),
            h.dispatchEvent(a)
        }, !1),
        this.addEventListener = function() {
            h.addEventListener.apply(h, arguments)
        }
        ,
        this.removeEventListener = function() {
            h.removeEventListener.apply(h, arguments)
        }
        ,
        this.show = function() {
            document.addEventListener("touchmove", c, !1),
            h.style.display = "block",
            window.scrollTo(0, 0)
        }
        ,
        this.hide = function() {
            document.removeEventListener("touchmove", c),
            window.scrollTo(0, -i.top),
            g.body.removeChild(h)
        }
    }
    function e(a, b) {
        this.request = a,
        this.response = b;
        var c = 0
          , d = {};
        this.on = function(a, b) {
            d[a] = b
        }
        ,
        this.next = function() {
            var b = m[c++];
            b ? a[b.__name__] ? b(this) : this.next() : this.end()
        }
        ,
        this.reset = function() {
            c = 0,
            d.reset && d.reset.call(this)
        }
        ,
        this.end = function() {
            d.end && d.end.call(this)
        }
    }
    function f(a, b) {
        b.__name__ = a,
        m.push(b)
    }
    var g = a.document
      , h = a.navigator.userAgent
      , i = h.match(/WindVane[\/\s]([\d\.\_]+)/);
    i && (i = i[1]);
    var j, k, l = h.match(/AliApp\(([^\/]+)\/([\d\.\_]+)\)/i);
    l && (j = l[1],
    k = l[2]),
    b.mtop = b.mtop || {},
    b.mtop.middleware = {};
    var m = [];
    b.mtop.middleware.pipe = function(a, b) {
        return new e(a,b)
    }
    ,
    b.mtop.middleware.add = f,
    f("LoginRequest", function(a) {
        function c() {
            a.reset()
        }
        function d() {
            a.response && a.response.ret.push("MW_ERROR::LOGIN_FAILURE"),
            a.end()
        }
        function e() {
            a.response && a.response.ret.push("MW_ERROR::WIDGET_CANCEL"),
            a.end()
        }
        var f = (a.response && a.response.ret || []).join(",");
        f.indexOf("SESSION_EXPIRED") > -1 || f.indexOf("SID_INVALID") > -1 || f.indexOf("AUTH_REJECT") > -1 || f.indexOf("NEED_LOGIN") > -1 ? b.login.goLogin(function(a) {
            "SUCCESS" === a ? c() : "CANCEL" === a ? e() : d()
        }) : a.next()
    }),
    f("AntiCreep", function(b) {
        function c() {
            h.removeEventListener("close", c),
            a.removeEventListener("message", e),
            b.response && b.response.ret.push("MW_ERROR::WIDGET_CANCEL"),
            b.end()
        }
        function e() {
            h.removeEventListener("close", c),
            a.removeEventListener("message", e);
            var d = JSON.parse(g.data) || {};
            if (d && "child" === d.type) {
                var f;
                try {
                    f = JSON.parse(decodeURIComponent(d.content)),
                    "string" == typeof f && (f = JSON.parse(f))
                } catch (g) {
                    f = null
                }
                if (f) {
                    for (var i in f)
                        b.request[i] = f[i];
                    b.reset()
                } else
                    b.response && b.response.ret.push("MW_ERROR::SM_FAILURE"),
                    b.end();
                h.hide()
            } else
                b.end()
        }
        var f = (b.response && b.response.ret || []).join(",");
        if (!l && f.indexOf("RGV587_ERROR::SM") > -1 && b.response.data.url) {
            var g = b.response.data.url
              , h = new d("",g);
            h.addEventListener("close", c, !1),
            a.addEventListener("message", e, !1),
            h.show()
        } else
            b.next()
    }),
    f("AntiFlood", function(a) {
        var b = (a.response && a.response.ret || []).join(",");
        if (!l && b.indexOf("FAIL_SYS_USER_VALIDATE") > -1 && a.response.data.url) {
            var c = a.response.data.url;
            location.href = c
        } else
            a.next()
    })
}(window, window.lib || (window.lib = {}));
!function(a, b) {
    function c(a) {
        Object.defineProperty(this, "val", {
            value: a.toString(),
            enumerable: !0
        }),
        this.gt = function(a) {
            return c.compare(this, a) > 0
        }
        ,
        this.gte = function(a) {
            return c.compare(this, a) >= 0
        }
        ,
        this.lt = function(a) {
            return c.compare(this, a) < 0
        }
        ,
        this.lte = function(a) {
            return c.compare(this, a) <= 0
        }
        ,
        this.eq = function(a) {
            return 0 === c.compare(this, a)
        }
    }
    b.env = b.env || {},
    c.prototype.toString = function() {
        return this.val
    }
    ,
    c.prototype.valueOf = function() {
        for (var a = this.val.split("."), b = [], c = 0; c < a.length; c++) {
            var d = parseInt(a[c], 10);
            isNaN(d) && (d = 0);
            var e = d.toString();
            e.length < 5 && (e = Array(6 - e.length).join("0") + e),
            b.push(e),
            1 === b.length && b.push(".")
        }
        return parseFloat(b.join(""))
    }
    ,
    c.compare = function(a, b) {
        a = a.toString().split("."),
        b = b.toString().split(".");
        for (var c = 0; c < a.length || c < b.length; c++) {
            var d = parseInt(a[c], 10)
              , e = parseInt(b[c], 10);
            if (window.isNaN(d) && (d = 0),
            window.isNaN(e) && (e = 0),
            e > d)
                return -1;
            if (d > e)
                return 1
        }
        return 0
    }
    ,
    b.version = function(a) {
        return new c(a)
    }
}(window, window.lib || (window.lib = {})),
function(a, b) {
    b.env = b.env || {};
    var c = a.location.search.replace(/^\?/, "");
    if (b.env.params = {},
    c)
        for (var d = c.split("&"), e = 0; e < d.length; e++) {
            d[e] = d[e].split("=");
            try {
                b.env.params[d[e][0]] = decodeURIComponent(d[e][1])
            } catch (f) {
                b.env.params[d[e][0]] = d[e][1]
            }
        }
}(window, window.lib || (window.lib = {})),
function(a, b) {
    b.env = b.env || {};
    var c, d = a.navigator.userAgent;
    if (c = d.match(/Windows\sPhone\s(?:OS\s)?([\d\.]+)/))
        b.env.os = {
            name: "Windows Phone",
            isWindowsPhone: !0,
            version: c[1]
        };
    else if (d.match(/Safari/) && (c = d.match(/Android[\s\/]([\d\.]+)/)))
        b.env.os = {
            version: c[1]
        },
        d.match(/Mobile\s+Safari/) ? (b.env.os.name = "Android",
        b.env.os.isAndroid = !0) : (b.env.os.name = "AndroidPad",
        b.env.os.isAndroidPad = !0);
    else if (c = d.match(/(iPhone|iPad|iPod)/)) {
        var e = c[1];
        (c = d.match(/OS ([\d_\.]+) like Mac OS X/)) && (b.env.os = {
            name: e,
            isIPhone: "iPhone" === e || "iPod" === e,
            isIPad: "iPad" === e,
            isIOS: !0,
            version: c[1].split("_").join(".")
        })
    }
    b.env.os || (b.env.os = {
        name: "unknown",
        version: "0.0.0"
    }),
    b.version && (b.env.os.version = b.version(b.env.os.version))
}(window, window.lib || (window.lib = {})),
function(a, b) {
    b.env = b.env || {};
    var c, d = a.navigator.userAgent;
    (c = d.match(/(?:UCWEB|UCBrowser\/)([\d\.]+)/)) ? b.env.browser = {
        name: "UC",
        isUC: !0,
        version: c[1]
    } : (c = d.match(/MQQBrowser\/([\d\.]+)/)) ? b.env.browser = {
        name: "QQ",
        isQQ: !0,
        version: c[1]
    } : (c = d.match(/(?:Firefox|FxiOS)\/([\d\.]+)/)) ? b.env.browser = {
        name: "Firefox",
        isFirefox: !0,
        version: c[1]
    } : (c = d.match(/MSIE\s([\d\.]+)/)) || (c = d.match(/IEMobile\/([\d\.]+)/)) ? (b.env.browser = {
        version: c[1]
    },
    d.match(/IEMobile/) ? (b.env.browser.name = "IEMobile",
    b.env.browser.isIEMobile = !0) : (b.env.browser.name = "IE",
    b.env.browser.isIE = !0),
    d.match(/Android|iPhone/) && (b.env.browser.isIELikeWebkit = !0)) : (c = d.match(/(?:Chrome|CriOS)\/([\d\.]+)/)) ? (b.env.browser = {
        name: "Chrome",
        isChrome: !0,
        version: c[1]
    },
    d.match(/Version\/[\d+\.]+\s*Chrome/) && (b.env.browser.name = "Chrome Webview",
    b.env.browser.isWebview = !0)) : d.match(/Safari/) && (c = d.match(/Android[\s\/]([\d\.]+)/)) ? b.env.browser = {
        name: "Android",
        isAndroid: !0,
        version: c[1]
    } : d.match(/iPhone|iPad|iPod/) && (d.match(/Safari/) && (c = d.match(/Version\/([\d\.]+)/)) ? b.env.browser = {
        name: "Safari",
        isSafari: !0,
        version: c[1]
    } : (c = d.match(/OS ([\d_\.]+) like Mac OS X/)) && (b.env.browser = {
        name: "iOS Webview",
        isWebview: !0,
        version: c[1].replace(/\_/g, ".")
    })),
    b.env.browser || (b.env.browser = {
        name: "unknown",
        version: "0.0.0"
    }),
    b.version && (b.env.browser.version = b.version(b.env.browser.version))
}(window, window.lib || (window.lib = {})),
function(a, b) {
    b.env = b.env || {};
    var c = a.navigator.userAgent;
    b.env.thirdapp = c.match(/Weibo/i) ? {
        appname: "Weibo",
        isWeibo: !0
    } : c.match(/MicroMessenger/i) ? {
        appname: "Weixin",
        isWeixin: !0
    } : !1
}(window, window.lib || (window.lib = {})),
function(a, b) {
    b.env = b.env || {};
    var c, d, e = a.navigator.userAgent;
    (d = e.match(/WindVane[\/\s]([\d\.\_]+)/)) && (c = d[1]);
    var f = !1
      , g = ""
      , h = ""
      , i = ""
      , j = a._ua_popLayer || ""
      , k = !1
      , l = "";
    (d = e.match(/AliApp\(([A-Z\-]+)\/([\d\.]+)\)/i)) && (f = !0,
    g = d[1],
    i = d[2],
    h = g.indexOf("-PD") > 0 ? b.env.os.isIOS ? "iPad" : b.env.os.isAndroid ? "AndroidPad" : b.env.os.name : b.env.os.name),
    !g && e.indexOf("TBIOS") > 0 && (g = "TB"),
    j && (d = j.match(/PopLayer\/([\d\.]+)/i)) && (k = !0,
    l = d[1]),
    b.env.aliapp = f ? {
        windvane: b.version(c || "0.0.0"),
        appname: g || "unkown",
        version: b.version(i || "0.0.0"),
        platform: h || b.env.os.name,
        poplayer: k || !1,
        poplayerVersion: b.version(l || "0.0.0")
    } : !1,
    b.env.taobaoApp = b.env.aliapp
}(window, window.lib || (window.lib = {}));
;(function(win, lib, undef) {
    var Promise = win.Promise;
    var doc = win.document;
    var ua = win.navigator.userAgent;
    var hostname = location.hostname;
    var search = win.location.search;
    var WindVaneVersion = ua.match(/WindVane[\/\s]([\d\.\_]+)/);
    var AliApp = ua.match(/AliApp\(([^\/]+)\/([\d\.\_]+)\)/i);
    var isTaobaoApp = !!(AliApp && AliApp[1] === 'TB' && WindVaneVersion && parseFloat(WindVaneVersion[1]) > 5.2);
    var SUPPORT_HOST = ['taobao.net', 'taobao.com'];
    var HOST_REGEXP = new RegExp('([^.]*?)\\.?((?:' + SUPPORT_HOST.join(')|(?:').replace(/\./g, '\\.') + '))','i');
    var matchedHost = hostname.match(HOST_REGEXP) || [];
    var MAIN_DOMAIN = (function() {
        var host = matchedHost[2] || 'taobao.com';
        if (host.match(/\.?taobao\.net$/)) {
            return 'taobao.net';
        } else {
            return 'taobao.com';
        }
    })();
    var SUB_DOMAIN = (function() {
        var host = MAIN_DOMAIN;
        var type = matchedHost[1] || 'm';
        if (host === 'taobao.net') {
            type = 'waptest';
        }
        return type;
    })();
    var PREFIX = 'login';
    /**
 * @namespace lib
 */
    /**
 * @namespace login
 * @memberof lib
 */
    lib.login = lib.login || {};
    /**
 * @member config
 * @memberof lib.login
 * @property {String} loginName - 登录页面的地址
 * @property {String} logoutName - 注销页面的地址
 * @property {String} subDomain - 二级域名
 */
    var config = {
        loginName: 'login.htm',
        logoutName: 'logout.htm',
        subDomain: SUB_DOMAIN
    };
    lib.login.config = config;
    function readCookie(name) {
        var matched = new RegExp('(?:^|;\\s*)' + name + '\\=([^;]+)(?:;\\s*|$)').exec(doc.cookie);
        if (matched) {
            return matched[1];
        } else {
            return undef;
        }
    }
    function preventMove(e) {
        e.preventDefault();
        return false;
    }
    function FrameWidget(text, url) {
        var that = this;
        var dpr = win.dpr || 1;
        var widget = document.createElement('div');
        var rect = document.documentElement.getBoundingClientRect();
        var width = Math.max(rect.width, window.innerWidth) / dpr;
        var height = Math.max(rect.height, window.innerHeight) / dpr;
        widget.style.cssText = ['-webkit-transform:scale(' + dpr + ') translateZ(0)', '-ms-transform:scale(' + dpr + ') translateZ(0)', 'transform:scale(' + dpr + ') translateZ(0)', '-webkit-transform-origin:0 0', '-ms-transform-origin:0 0', 'transform-origin:0 0', 'width:' + width + 'px', 'height:' + height + 'px', 'z-index:999999', 'position:absolute', 'left:0', 'top:0px', 'background:#FFF', 'display:none'].join(';');
        var title = document.createElement('div');
        title.style.cssText = ['width:100%', 'height:' + 52 + 'px', 'background:#EEE', 'line-height:' + 52 + 'px', 'text-align:left', 'box-sizing:border-box', 'padding-left:' + 20 + 'px', 'position:absolute', 'left:0', 'top:0', 'font-size:' + 16 + 'px', 'font-weight:bold', 'color:#333'].join(';');
        title.innerText = text;
        var close = document.createElement('a');
        close.style.cssText = ['display:block', 'position:absolute', 'right:0', 'top:0', 'height:' + 52 + 'px', 'line-height:' + 52 + 'px', 'padding:0 ' + 20 + 'px', 'color:#999'].join(';');
        close.innerText = '关闭';
        var content = document.createElement('iframe');
        content.style.cssText = ['width:100%', 'height:100%', 'border:0', 'overflow:hidden'].join(';');
        title.appendChild(close);
        widget.appendChild(title);
        widget.appendChild(content);
        doc.body.appendChild(widget);
        content.src = url;
        close.addEventListener('click', function() {
            that.hide();
            var ev = doc.createEvent('HTMLEvents');
            ev.initEvent('close', false, false);
            widget.dispatchEvent(ev);
        }, false);
        this.addEventListener = function() {
            widget.addEventListener.apply(widget, arguments);
        }
        this.removeEventListener = function() {
            widget.removeEventListener.apply(widget, arguments);
        }
        this.show = function() {
            document.addEventListener('touchmove', preventMove, false);
            widget.style.display = 'block';
            window.scrollTo(0, 0);
        }
        this.hide = function() {
            document.removeEventListener('touchmove', preventMove);
            window.scrollTo(0, -rect.top);
            doc.body.removeChild(widget);
        }
    }
    /**
 * 检查是否登录
 * @function
 * @return {Boolean} 是否登录
 * @memberof lib.login
 */
    function isLogin(callback) {
        if (callback && typeof callback === 'function' && lib.mtop) {
            lib.mtop.request({
                api: 'mtop.user.getUserSimple',
                v: '1.0',
                data: {
                    'isSec': 0
                },
                H5Request: true
            }, function(json) {
                if (json.retType === lib.mtop.RESPONSE_TYPE.SUCCESS) {
                    callback(true, json);
                } else if (json.retType === lib.mtop.RESPONSE_TYPE.SESSION_EXPIRED) {
                    callback(false, json);
                } else {
                    callback(undef, json);
                }
            });
        } else {
            var nick = this.getUserNick();
            return !!nick
        }
    }
    lib.login.isLogin = isLogin;
    /**
 * 是否登录的回调
 * @callback loginCallback
 * @param {Boolean} status - 是否登录的状态
 * @param {Object} profile - 当前登录用户的信息
 */
    /**
 * 异步检查是否登录
 * @function
 * @param {loginCallback} [callback] - 回调函数
 * @return {Promise} Promise实例
 * @memberof lib.login
 */
    function isLoginAsync(callback) {
        var deferred;
        if (Promise) {
            deferred = {};
            deferred.promise = new Promise(function(resolve, reject) {
                deferred.resolve = resolve;
                deferred.reject = reject;
            }
            );
        }
        this.isLogin(function(status, profile) {
            callback && callback(status, profile);
            if (status === true) {
                deferred && deferred.resolve(profile);
            } else {
                deferred && deferred.reject(profile);
            }
        });
        if (deferred) {
            return deferred.promise;
        }
    }
    lib.login.isLoginAsync = isLoginAsync;
    /**
 * 获得用户昵称
 * @function
 * @return {String} 用户昵称
 * @memberof lib.login
 */
    function getUserNick(callback) {
        if (callback && typeof callback === 'function') {
            this.isLogin(function(is, json) {
                if (is === true && json && json.data && json.data.nick) {
                    callback(json.data.nick);
                } else if (is === false) {
                    callback('');
                } else {
                    callback(undef);
                }
            });
        } else {
            var nick = '';
            var wapnick = readCookie('_w_tb_nick');
            // 原先wap登录的cookie
            var tbnick = readCookie('_nk_') || readCookie('snk');
            // pc登录的cookie
            var subnick = readCookie('sn');
            // 子帐号登录的cookie
            if (wapnick && wapnick.length > 0 && wapnick != 'null') {
                nick = decodeURIComponent(wapnick);
                // 中文会encode，需要decode
            } else if (tbnick && tbnick.length > 0 && tbnick != 'null') {
                nick = unescape(unescape(tbnick).replace(/\\u/g, '%u'));
            } else if (subnick && subnick.length > 0 && subnick != 'null') {
                nick = decodeURIComponent(subnick);
            }
            nick = nick.replace(/\</g, '&lt;').replace(/\>/g, '&gt;');
            return nick;
        }
    }
    lib.login.getUserNick = getUserNick;
    /**
 * 异步获得用户昵称
 * @function
 * @param {Function} [callback] - 回调函数
 * @return {Promise} Promise实例
 * @memberof lib.login
 */
    function getUserNickAsync(callback) {
        var deferred;
        if (Promise) {
            deferred = {};
            deferred.promise = new Promise(function(resolve, reject) {
                deferred.resolve = resolve;
                deferred.reject = reject;
            }
            );
        }
        this.getUserNick(function(nick) {
            callback && callback(nick);
            if (!!nick) {
                deferred && deferred.resolve(nick);
            } else {
                deferred && deferred.reject();
            }
        });
        if (deferred) {
            return deferred.promise;
        }
    }
    lib.login.getUserNickAsync = getUserNickAsync;
    /**
 * 获得登录/注销地址
 * @function
 * @param {String} type - login或logout类型
 * @param {Object} param - 需要透传的参数
 * @return {String} 生成的地址
 * @memberof lib.login
 */
    function generateUrl(type, params) {
        var url = '//' + PREFIX + '.' + config.subDomain + '.' + MAIN_DOMAIN + '/' + config[(type || 'login') + 'Name'];
        if (params) {
            var qs = [];
            for (var key in params) {
                qs.push(key + '=' + encodeURIComponent(params[key]));
            }
            url += '?' + qs.join('&');
        }
        return url;
    }
    lib.login.generateUrl = generateUrl;
    function redirect(url, isReplace) {
        if (isReplace) {
            location.replace(url);
        } else {
            // 以下是为了兼容Android2.2部分机型，但是在chrome 53.0.2785.116及其以上会失效
            // var anchorElement = doc.createElement('a');
            // var clickEvent = doc.createEvent('HTMLEvents');
            // anchorElement.style.display = 'none';
            // anchorElement.href = url;
            // doc.body.appendChild(anchorElement);
            // clickEvent.initEvent('click', false, true);
            // anchorElement.dispatchEvent(clickEvent);
            location.href = url;
        }
    }
    function widget(type, options, callback) {
        var redirectUrl = location.protocol + '//h5.' + config.subDomain + '.taobao.com/' + (config.subDomain === 'waptest' ? 'src' : 'other') + '/' + type + 'end.html?origin=' + encodeURIComponent(location.protocol + '//' + location.hostname);
        var url = generateUrl(type, {
            ttid: 'h5@iframe',
            tpl_redirect_url: redirectUrl,
        });
        var widget = new FrameWidget(options.title || '您需要登录才能继续访问',url);
        function closeHandler(e) {
            widget.removeEventListener('close', closeHandler);
            win.removeEventListener('message', messageHandler);
            callback('CANCEL');
        }
        function messageHandler(e) {
            var data = e.data || {};
            if (data && data.type === 'child' && data.content.indexOf('SUCCESS') > -1) {
                widget.removeEventListener('close', closeHandler);
                win.removeEventListener('message', messageHandler);
                widget.hide();
                callback('SUCCESS');
            } else {
                callback('FAILURE');
            }
        }
        widget.addEventListener('close', closeHandler, false);
        win.addEventListener('message', messageHandler, false);
        widget.show();
    }
    function native(type, options, callback) {
        var url = generateUrl(type, {
            wvLoginCallback: 'wvLoginCallback'
        });
        win['wvLoginCallback'] = function(ret) {
            delete win['wvLoginCallback'];
            if (ret.indexOf(':SUCCESS') > -1) {
                callback('SUCCESS');
            } else if (ret.indexOf(':CANCEL') > -1) {
                callback('CANCEL');
            } else {
                callback('FAILURE');
            }
        }
        redirect(url);
    }
    function go(type, options, callback) {
        if (typeof options === 'function') {
            callback = options;
            options = null;
        } else if (typeof options === 'string') {
            options = {
                redirectUrl: options
            };
        }
        options = options || {};
        if (callback && isTaobaoApp) {
            // 有回调且在手淘客户端里，则用客户端的登录框
            native(type, options, callback);
        } else if (callback && !AliApp && type === 'login') {
            // 有回调且不在阿里系客户端里，且发起的是异步登录，则用iframe弹窗
            widget(type, options, callback);
        } else {
            // 其余情况都直接跳转
            var url = generateUrl(type, {
                tpl_redirect_url: options.redirectUrl || location.href
            });
            redirect(url, options.replace);
        }
    }
    function goAsync(type, options, callback) {
        var deferred;
        if (Promise) {
            deferred = {};
            deferred.promise = new Promise(function(resolve, reject) {
                deferred.resolve = resolve;
                deferred.reject = reject;
            }
            );
        }
        go(type, options, function(status) {
            callback && callback(status);
            if (status === 'SUCCESS') {
                deferred && deferred.resolve(status);
            } else {
                deferred && deferred.reject(status);
            }
        });
        if (deferred) {
            return deferred.promise;
        }
    }
    /**
 * 跳转登录页面
 * @function
 * @param {String} [url=当前页面地址] - 登录成功后跳转的页面
 * @memberof lib.login
 */
    function goLogin(url) {
        go('login', url);
    }
    lib.login.goLogin = goLogin;
    /**
 * 异步登录
 * @function
 * @param {Function} [callback] - 回调函数
 * @return {Promise} Promise实例
 * @memberof lib.login
 */
    function goLoginAsync(callback) {
        return goAsync('login', callback);
    }
    lib.login.goLoginAsync = goLoginAsync;
    /**
 * 跳转注销页面
 * @function
 * @param {String} [url=当前页面地址] - 注销成功后跳转的页面
 * @memberof lib.login
 */
    function goLogout(url) {
        go('logout', url);
    }
    lib.login.goLogout = goLogout;
    /**
 * 异步注销
 * @function
 * @param {Function} [callbacak] - 回调函数
 * @return {Promise} Promise实例
 * @memberof lib.login
 */
    function goLogoutAsync(callback) {
        return goAsync('logout', callback);
    }
    lib.login.goLogoutAsync = goLogoutAsync;
})(window, window['lib'] || (window['lib'] = {}));
!function(a, b) {
    function c(a, b) {
        for (var c in b)
            a[c] = b[c];
        return a
    }
    function d(a) {
        this.callback && this.callback(a, !0)
    }
    function e(a) {
        this.callback && this.callback(a, !1)
    }
    function f(a) {
        this._options = c({
            mode: "msg",
            text: "网页提示",
            useTap: !1
        }, a || {}),
        this._init()
    }
    var g, h, i, j, k, l, m = a.document, n = (m.body,
    !1);
    g = m.createElement("div"),
    g.className = "c-float-popWrap msgMode hide",
    g.innerHTML = ['<div class="pop-mask" style=""></div><div class="c-float-modePop">', '<div class="warnMsg"></div>', '<div class="content"></div>', '<div class="doBtn">', '<button class="ok">确定</button>', '<button class="cancel">取消</button>', "</div>", "</div>"].join(""),
    h = g.querySelector(".warnMsg"),
    i = g.querySelector(".content"),
    j = g.querySelector(".doBtn .ok"),
    k = g.querySelector(".doBtn .cancel"),
    c(f.prototype, {
        _init: function() {
            var b = this
              , c = b._options
              , f = c.mode
              , l = c.text
              , o = c.content
              , p = c.callback
              , q = c.background
              , r = c.useTap ? "touchend" : "click"
              , s = g.className;
            s = s.replace(/(msg|alert|confirm)Mode/i, f + "Mode"),
            g.className = s,
            q && (g.firstChild.style.background = q),
            l && (h.innerHTML = l),
            o && (i.innerHTML = o),
            j.removeEventListener("touchend", d),
            j.removeEventListener("click", d),
            k.removeEventListener("touchend", d),
            k.removeEventListener("click", d),
            j.addEventListener(r, d, !1),
            k.addEventListener(r, e, !1),
            j.callback = k.callback = function() {
                p.apply(b, arguments)
            }
            ,
            n || (n = !0,
            m.body.appendChild(g),
            a.addEventListener("resize", function() {
                setTimeout(function() {
                    b._pos()
                }, 500)
            }, !1))
        },
        _pos: function() {
            var b, c, d, e, f, h, i, j, k = this;
            k.isHide() || (b = m.body.getBoundingClientRect(),
            c = -b.top,
            d = -b.left,
            e = a.innerWidth,
            f = a.innerHeight,
            h = g.getBoundingClientRect(),
            i = h.width,
            j = h.height,
            g.style.top = c + (f - j) / 2 + "px",
            g.style.left = d + (e - i) / 2 + "px")
        },
        isShow: function() {
            return g.className.indexOf("show") > -1
        },
        isHide: function() {
            return g.className.indexOf("hide") > -1
        },
        _cbShow: function() {
            var a = this
              , b = a._options
              , c = b.onShow;
            g.style.opacity = "1",
            g.className = g.className.replace(/\b(?:show|hide)/, "show"),
            c && c.call(a)
        },
        show: function() {
            var a = this;
            l && (clearTimeout(l),
            l = void 0),
            a.isShow() ? a._cbShow() : (g.style.opacity = "0",
            g.className = g.className.replace("hide", ""),
            a._pos(),
            setTimeout(function() {
                a._cbShow()
            }, 300),
            setTimeout(function() {
                g.style.webkitTransition = "opacity 0.4s linear 0",
                g.style.opacity = "1"
            }, 1))
        },
        _cbHide: function() {
            var a = this
              , b = a._options
              , c = b.onHide;
            g.style.opacity = "0",
            g.className = g.className.replace(/\s*show|hide/, "") + " hide",
            c && c.call(a)
        },
        hide: function() {
            var a = this;
            a.isHide() ? a._cbHide() : (g.style.opacity = "1",
            g.className = g.className.replace("show", ""),
            setTimeout(function() {
                a._cbHide()
            }, 300),
            setTimeout(function() {
                g.style.webkitTransition = "opacity 0.4s linear 0",
                g.style.opacity = "0"
            }, 1))
        },
        flash: function(a) {
            var b = this;
            opt = b._options,
            opt.onShow = function() {
                l = setTimeout(function() {
                    l && b.hide()
                }, a)
            }
            ,
            b.show()
        }
    }),
    b.notification = new function() {
        this.simple = function(a, b, c) {
            2 == arguments.length && "number" == typeof arguments[1] && (c = arguments[1],
            b = void 0);
            var d = new f({
                mode: "msg",
                text: a,
                background: b
            });
            return d.flash(c || 2e3),
            d
        }
        ,
        this.msg = function(a, b) {
            return new f(c({
                mode: "msg",
                text: a
            }, b || {}))
        }
        ,
        this.alert = function(a, b, d) {
            return new f(c({
                mode: "alert",
                text: a,
                callback: b
            }, d || {}))
        }
        ,
        this.confirm = function(a, b, d, e) {
            return new f(c({
                mode: "confirm",
                text: a,
                content: b,
                callback: d
            }, e || {}))
        }
        ,
        this.pop = function(a) {
            return new f(a)
        }
    }
}(window, window.lib || (window.lib = {}));
!function() {
    var a = window.location.host && window.location.host.match(".*\\m\\.(taobao|tmall)\\.com.*");
    return window.namespace ? (console.warn("namespace aleady exist"),
    void 0) : (window.namespace = function(b, c) {
        if (2 === arguments.length) {
            for (var d, e = b.split("."), f = window, g = 0; g < e.length; g++) {
                if (d = e[g],
                g === e.length - 1) {
                    f[d] ? (console.error("namespace aleady exist :" + b),
                    a && (console.warn("forse replacement"),
                    f[d] = c)) : f[d] = c;
                    break
                }
                f[d] || (f[d] = {}),
                f = f[d]
            }
            return f
        }
        if (1 === arguments.length)
            try {
                for (var h = b.split("."), i = window; h.length && i; )
                    i = i[h.shift()];
                return i
            } catch (j) {
                return void 0
            }
    }
    ,
    window._define = function(a, b) {
        var c = {}
          , d = c.exports = {};
        namespace(a, b(null, d, c) || c.exports)
    }
    ,
    namespace("lib.define", function(a, b) {
        namespace(a, b())
    }),
    void 0)
}();
!function(a, b) {
    function c(a) {
        var b = {};
        Object.defineProperty(this, "params", {
            set: function(a) {
                if ("object" == typeof a) {
                    for (var c in b)
                        delete b[c];
                    for (var c in a)
                        b[c] = a[c]
                }
            },
            get: function() {
                return b
            },
            enumerable: !0
        }),
        Object.defineProperty(this, "search", {
            set: function(a) {
                if ("string" == typeof a) {
                    0 === a.indexOf("?") && (a = a.substr(1));
                    var c = a.split("&");
                    for (var d in b)
                        delete b[d];
                    for (var e = 0; e < c.length; e++) {
                        var f = c[e].split("=");
                        if (f[0])
                            try {
                                b[decodeURIComponent(f[0])] = decodeURIComponent(f[1] || "")
                            } catch (g) {
                                b[f[0]] = f[1] || ""
                            }
                    }
                }
            },
            get: function() {
                var a = [];
                for (var c in b)
                    if (b[c])
                        try {
                            a.push(encodeURIComponent(c) + "=" + encodeURIComponent(b[c]))
                        } catch (d) {
                            a.push(c + "=" + b[c])
                        }
                    else
                        try {
                            a.push(encodeURIComponent(c))
                        } catch (d) {
                            a.push(c)
                        }
                return a.length ? "?" + a.join("&") : ""
            },
            enumerable: !0
        });
        var c;
        Object.defineProperty(this, "hash", {
            set: function(a) {
                a && a.indexOf("#") < 0 && (a = "#" + a),
                c = a || ""
            },
            get: function() {
                return c
            },
            enumerable: !0
        }),
        this.set = function(a) {
            a = a || "";
            var b;
            if (!(b = a.match(new RegExp("^([a-z0-9-]+:)?[/]{2}(?:([^@/:?]+)(?::([^@/:]+))?@)?([^:/?#]+)(?:[:]([0-9]+))?([/][^?#;]*)?(?:[?]([^?#]*))?(#[^#]*)?$","i"))))
                throw new Error("Wrong uri scheme.");
            this.protocol = b[1] || location.protocol,
            this.username = b[2] || "",
            this.password = b[3] || "",
            this.hostname = this.host = b[4],
            this.port = b[5] || "",
            this.pathname = b[6] || "/",
            this.search = b[7] || "",
            this.hash = b[8] || "",
            this.origin = this.protocol + "//" + this.hostname
        }
        ,
        this.toString = function() {
            var a = this.protocol + "//";
            return this.username && (a += this.username,
            this.password && (a += ":" + this.password),
            a += "@"),
            a += this.host,
            this.port && "80" !== this.port && (a += ":" + this.port),
            this.pathname && (a += this.pathname),
            this.search && (a += this.search),
            this.hash && (a += this.hash),
            a
        }
        ,
        a && this.set(a.toString())
    }
    b.httpurl = function(a) {
        return new c(a)
    }
}(window, window.lib || (window.lib = {}));
!function(a, b) {
    b.secureFilters = function(a) {
        var b = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F-\x9F]/g
          , c = /[^\t\n\v\f\r ,\.0-9A-Z_a-z\-\u00A0-\uFFFF]/g
          , d = String(a || "");
        return d = d.replace(b, " "),
        d.replace(c, function(a) {
            var b = a.charCodeAt(0);
            switch (b) {
            case 34:
                return "&quot;";
            case 38:
                return "&amp;";
            case 60:
                return "&lt;";
            case 62:
                return "&gt;";
            default:
                if (100 > b) {
                    var c = b.toString(10);
                    return "&#" + c + ";"
                }
                var d = b.toString(16).toUpperCase();
                return "&#x" + d + ";"
            }
        })
    }
}(window, window.lib || (window.lib = {}));
!function(a, b) {
    function c(a, b) {
        var c, d, e, f = null, g = 0, h = function() {
            g = Date.now(),
            f = null,
            e = a.apply(c, d)
        };
        return function() {
            var i = Date.now()
              , j = b - (i - g);
            return c = this,
            d = arguments,
            0 >= j ? (clearTimeout(f),
            f = null,
            g = i,
            e = a.apply(c, d)) : f || (f = setTimeout(h, j)),
            e
        }
    }
    function d(a) {
        var b = null != navigator.userAgent.match(/WindVane/i);
        b && window.WindVane ? WindVane.call("TBDeviceInfo", "getInfo", {}, function(b) {
            b && b.network && (C = b.network,
            a && a())
        }, function() {
            a && a()
        }) : a && a()
    }
    function e(a) {
        try {
            var b = new Image;
            b.src = "",
            b.onload = function() {
                E = 2 === b.height ? !0 : !1,
                a && a()
            }
            ,
            b.onerror = function() {
                E = !1,
                a && a()
            }
        } catch (c) {
            a && a()
        }
    }
    function f(a, b) {
        for (var c in b)
            b.hasOwnProperty(c) && (a[c] = b[c]);
        return a
    }
    function g(a, b) {
        if (a) {
            if (b || (b = {
                x: 0,
                y: 0
            }),
            a != window)
                var c = a.getBoundingClientRect()
                  , d = c.left
                  , e = c.top
                  , f = c.right
                  , g = c.bottom;
            else
                d = 0,
                e = 0,
                f = d + a.innerWidth,
                g = e + a.innerHeight;
            return {
                left: d,
                top: e,
                right: f + b.x,
                bottom: g + b.y
            }
        }
    }
    function h(a, b) {
        var c = b.right > a.left && b.left < a.right
          , d = b.bottom > a.top && b.top < a.bottom;
        return c && d
    }
    function i() {
        {
            var a = document.createElement("canvas");
            a.getContext("2d")
        }
        D = Array.prototype.slice.call(document.querySelectorAll("." + F.class)),
        D.length && D.forEach(function(a) {
            "1" == a.getAttribute("data-cache") && l(a)
        })
    }
    function j() {
        var a = F.dataSrc;
        D.length && D.forEach(function(b) {
            if ("true" != b.getAttribute("data-src-checked")) {
                var c = b.getAttribute(a)
                  , d = b.getAttribute("data-size")
                  , e = b.getAttribute("data-type")
                  , f = {};
                d && (f.size = d),
                e && (f.type = e),
                b.attributes["data-original"] && (f.isOriginal = !0),
                c && (b.setAttribute(a, G.getNewUrl(c, f)),
                b.setAttribute("data-src-checked", "true"))
            }
        })
    }
    function k() {
        var a = F.dataSrc
          , b = g(window, {
            x: F.lazyWidth,
            y: F.lazyHeight
        });
        D.length && D.forEach(function(c) {
            function d(b) {
                if (b.removeAttribute(a),
                "IMG" === b.tagName)
                    if (1 == b.getAttribute("data-cache")) {
                        var c = m(e);
                        b.setAttribute("src", c || e)
                    } else
                        b.setAttribute("src", e);
                else
                    b.style.backgroundImage = "url(" + e + ")";
                b.className = b.className.replace(new RegExp("(^|\\s)" + F.class + "(\\s|$)"), "")
            }
            var e = c.getAttribute(a)
              , f = g(c)
              , i = h(b, f);
            e && ("wifi" == C && r && F.enalbeIOSWifiLoadMore ? d(c) : i && d(c))
        })
    }
    function l(a) {
        var b = !!window.localStorage && !!document.createElement("canvas").getContext;
        if (b && "data" != a.src.substring(0, 4)) {
            var c = document.createElement("canvas")
              , d = c.getContext("2d");
            a.setAttribute("crossOrigin", "anonymous"),
            a.onload = function() {
                if (!this.getAttribute(F.dataSrc) && "data" != a.src.substring(0, 4)) {
                    var b = this.width
                      , e = this.height;
                    c.width = b,
                    c.height = e,
                    d.drawImage(this, 0, 0, b, e);
                    var f = c.toDataURL()
                      , g = {}
                      , h = this.src;
                    g[this.src] = f;
                    var i = localStorage.getItem(h)
                      , j = localStorage.getItem("h5_lib_img_cached_list")
                      , k = j ? JSON.parse(j) : [];
                    if (!i) {
                        if (localStorage.setItem("h5_lib_img_cached_url_" + h, f),
                        k.length >= 200) {
                            var l = k.shift();
                            localStorage.removeItem(l)
                        }
                        k.push("h5_lib_img_cached_url_" + h),
                        localStorage.setItem("h5_lib_img_cached_list", JSON.stringify(k))
                    }
                }
            }
        }
    }
    function m(a) {
        var b = !!window.localStorage
          , c = localStorage.getItem("h5_lib_img_cached_url_" + a);
        return b && c ? c : null
    }
    function n(a, b) {
        b = b || x;
        var c = B.square;
        if (!a || "string" != typeof a && "number" != typeof a)
            throw new Error("wrong size type");
        switch ("string" == typeof a && a.match(/^\d+x\d+$/) && (b == x || b == y ? a = a.split("x")[0] : "heightFixed" == b && (a = a.split("x")[1])),
        b) {
        case y:
            c = B.widths;
            break;
        case z:
            c = B.heights;
            break;
        case A:
            c = B.xzs
        }
        var d = c[c.length - 1]
          , e = c[0]
          , f = 0;
        if (t || (a = parseInt(a / 2)),
        a >= d)
            return d;
        if (e >= a)
            return e;
        for (var g = c.length; g >= 0; g--)
            if (c[g] <= a) {
                c[g] == a ? f = a : g < c.length - 1 && (f = c[g + 1]);
                break
            }
        return f
    }
    function o(a) {
        var b = F.defaultSize
          , c = F.q
          , d = F.sharpen
          , e = ""
          , f = F.defaultSize
          , g = x;
        switch ("[object Array]" == Object.prototype.toString.call(c) && (c = c[0]),
        a && (a.size && (f = a.size),
        a.type && a.type.match(new RegExp("^(" + [x, y, z, A].join("|") + ")$")) && (g = a.type)),
        b = n(f, g),
        g) {
        case x:
            b = b + "x" + b;
            break;
        case y:
            b += "x10000";
            break;
        case z:
            b = "10000x" + b;
            break;
        case A:
            b = b + "x" + b + "xz"
        }
        return e = "_" + b,
        e += c + d + ".jpg"
    }
    function p() {
        var a = c(k, 100);
        window.addEventListener("scroll", a, !1)
    }
    function q(a) {
        function b() {
            if ("[object Array]" == Object.prototype.toString.call(F.q))
                if (t)
                    F.q = C ? "wifi" == C ? F.q[0] : F.q[1] : F.q[0];
                else {
                    var a = parseInt(F.q[0].slice(1))
                      , b = parseInt(F.q[1].slice(1))
                      , c = a + 40 >= 90 ? "q90" : "q" + (a + 40)
                      , d = b + 45 >= 75 ? "q75" : "q" + (b + 45);
                    F.q = C ? "wifi" == C ? c : d : c
                }
            i(),
            e(function() {
                j(),
                F.enableLazyload && (p(),
                k())
            })
        }
        a = a || {},
        F = f(F, a),
        F.class = "." !== F.class.charAt(0) ? F.class : F.class.slice(1),
        F.size && (F.defaultSize = n(F.size)),
        d(b)
    }
    var r = (window.document,
    null != navigator.userAgent.match(/(iPhone\sOS)\s([\d_]+)/i))
      , s = (r && 3 == window.devicePixelRatio,
    window.devicePixelRatio ? window.devicePixelRatio : 1)
      , t = s >= 2
      , u = "gw.alicdn.com"
      , v = ""
      , w = /_(\d+x\d+|cy\d+i\d+|sum|m|b)?(xz|xc)?(q\d+)?(s\d+)?(\.jpg)?(_\.webp)?$/i
      , x = "square"
      , y = "widthFixed"
      , z = "heightFixed"
      , A = "xz"
      , B = {};
    B.widths = [110, 150, 170, 220, 240, 290, 450, 570, 580, 620, 790],
    B.heights = [170, 220, 340, 500],
    B.xzs = [72, 80, 88, 90, 100, 110, 120, 145, 160, 170, 180, 200, 230, 270, 290, 310, 360, 430, 460, 580, 640],
    B.square = [16, 20, 24, 30, 32, 36, 40, 48, 50, 60, 64, 70, 72, 80, 88, 90, 100, 110, 120, 125, 128, 145, 180, 190, 200, 200, 210, 220, 230, 240, 250, 270, 300, 310, 315, 320, 336, 360, 468, 490, 540, 560, 580, 600, 640, 720, 728, 760, 970],
    B.filterDomains = ["a.tbcdn.cn", "assets.alicdn.com"];
    var C, D, E = !1, F = {
        "class": "lib-img",
        size: "200x200",
        sharpen: "s150",
        dataSrc: "data-src",
        q: ["q50", "q30"],
        enableLazyload: !0,
        lazyHeight: 0,
        lazyWidth: 0,
        enableIOSWebp: !1,
        enalbeIOSWifiLoadMore: !1
    }, G = {
        getNewUrl: function(a, c) {
            if (!a || "string" != typeof a)
                return "";
            var d = F.defaultSize + "x" + F.defaultSize
              , e = F.q;
            "[object Array]" == Object.prototype.toString.call(e) && (e = e[0]);
            var f = "_" + d + e + F.sharpen + ".jpg";
            try {
                var g = new b.httpurl(a)
            } catch (h) {
                return console.log("[error]wrong img url:", a),
                a
            }
            {
                var i = g.host
                  , j = g.pathname;
                g.protocol
            }
            if (-1 != B.filterDomains.indexOf(i))
                return g.toString();
            var k = i.match(/(.+\.(?:alicdn|taobaocdn|taobao|mmcdn)\.com)/);
            if (k && k[0] != u && (g.host = u),
            c && c.isOriginal)
                return g.toString();
            var l = j.match(w);
            return c && "string" == typeof c ? f = o({
                size: c
            }) : c && "object" == typeof c && Object.keys(c).length > 0 && (f = o(c)),
            /\.gif/.test(j) ? g.toString() : (/\.png/.test(j) && (f = f.replace(/(q\d+)(s\d+)/, "")),
            E && !r && (/\.(png|gif)/.test(j) || (f += "_.webp")),
            l ? (l[1] || l[2] || l[3] || l[4]) && (g.pathname = j.replace(w, f)) : g.pathname = j.match(/_\.webp$/g) ? j.replace(/_\.webp$/g, f) : j + f,
            g.toString())
        },
        fireLazyload: function() {
            i(),
            j(),
            k()
        }
    };
    b.img = function() {
        return q.apply(G, arguments),
        G
    }
    ,
    b.img.defaultSrc = v
}(window, window.lib || (window.lib = {}));
/**
 * select menu 控件
 *
 * @author 景烁
 * @created 2014-07-31
 *
 * @requires lib.scroll
 *
 */
;(function(win, ctrl) {
    // 辅助方法：负责窗口弹出和收起
    var SelectBox = {
        open: function(selectContainer, onOpen) {
            if (!selectContainer)
                return;
            var selectBox = selectContainer.firstChild;
            selectContainer.style.opacity = 1;
            selectContainer.style.visibility = 'visible';
            // fix android 展示不出 selectContainer
            setTimeout(function() {
                selectBox.style.webkitTransform = 'translateY(0)';
                onOpen && onOpen();
            }, 0);
        },
        close: function(selectContainer, onClose) {
            if (!selectContainer)
                return;
            var selectBox = selectContainer.firstChild;
            selectBox.style.webkitTransform = 'translateY(100%)';
            setTimeout(function() {
                selectContainer.style.opacity = 0;
                selectContainer.style.visibility = 'hidden';
                onClose && onClose();
            }, 200);
        }
    };
    // main
    var incId = 0;
    var Klass = {
        container: 'ctrl-selectmenu',
        innerBox: 'ctrl-selectmenu-picker',
        header: 'ctrl-selectmenu-header',
        confirm: 'ctrl-selectmenu-btn-confirm',
        cancel: 'ctrl-selectmenu-btn-cancel',
        col: 'ctrl-selectmenu-col',
        option: 'ctrl-selectmenu-option',
        wrapper: 'ctrl-selectmenu-wrapper',
    };
    var SelectMenu = function(element, options) {
        /**
            控件规范
         */
        var that = this;
        var id = Date.now() + '-' + (++incId);
        // 每个控件有唯一的id
        var root = document.createDocumentFragment();
        // 文档片段，用于append时提高效率
        if (arguments.length === 1 && !(arguments[0]instanceof HTMLElement)) {
            // 参数个数的兼容判断
            options = arguments[0];
            element = null;
        }
        if (!element) {
            // 如果不是从已有DOM元素创建控件，则可以新建一个元素
            element = document.createElement('div');
        }
        root.appendChild(element);
        element.setAttribute('data-ctrl-name', 'selectmenu');
        element.setAttribute('data-ctrl-id', id);
        element.className = Klass.container;
        // 全局配置
        this.options = options;
        // --- 编写控件的属性
        // 编写控件的属性
        var title = options.title || '';
        Object.defineProperty(this, 'title', {
            get: function() {
                return title;
            },
            set: function(v) {
                if (v) {
                    title = v;
                    element.querySelector('.tip').innerHTML = v;
                } else {
                    throw new Error('Non expected value');
                }
            }
        });
        var confirmText = options.confirmText || '确定';
        Object.defineProperty(this, 'confirmText', {
            get: function() {
                return confirmText;
            },
            set: function(v) {
                if (v) {
                    confirmText = v;
                    element.querySelector('.' + Klass.confirm).innerHTML = v;
                } else {
                    throw new Error('Non expected value');
                }
            }
        });
        var cancelText = options.cancelText || '取消';
        Object.defineProperty(this, 'cancelText', {
            get: function() {
                return cancelText;
            },
            set: function(v) {
                if (v) {
                    cancelText = v;
                    element.querySelector('.' + Klass.cancel).innerHTML = v;
                } else {
                    throw new Error('Non expected value');
                }
            }
        });
        // -- vm属性的获取和设置
        var viewModel;
        Object.defineProperty(this, 'viewModel', {
            get: function() {
                return viewModel;
            },
            set: function(v) {
                if (v) {
                    viewModel = v;
                    that.syncViewModel();
                    // 自动同步数据和视图
                } else {
                    throw new Error('Non expected value');
                }
            }
        });
        // 同步数据和视图的方法
        this.syncViewModel = function() {
            var that = this;
            // 重新渲染
            this.render();
            // todo: 待验证是否必须。 延迟，等待dom ready
            setTimeout(function() {
                that.addEvents();
            }, 100);
        }
        ;
        // --- 事件代理
        this._events = {};
        this.addEventListener = function(type, fn) {
            if (!this._events[type]) {
                this._events[type] = [];
            }
            this._events[type].push(fn);
        }
        ;
        this.removeEventListener = function(type, fn) {
            if (!this._events[type]) {
                return;
            }
            var index = this._events[type].indexOf(fn);
            if (index > -1) {
                this._events[type].splice(index, 1);
            }
        }
        ;
        // 后可带参数
        // 执行自定义事件绑定
        this.execEvent = function(type) {
            if (!this._events[type]) {
                return;
            }
            var i = 0
              , l = this._events[type].length;
            if (!l) {
                return;
            }
            for (; i < l; i++) {
                this._events[type][i].apply(this, [].slice.call(arguments, 1));
            }
        }
        ;
        // 移除控件元素
        this.remove = function() {
            if (element.parentNode) {
                element.parentNode.removeChild(element);
            }
        }
        ;
        this.element = element;
        this.root = root;
        /**
            业务代码
         */
        var myScroll = {};
        var currentOptions = {};
        var selectedValue = {};
        // -- 拼装 select dom
        this.render = function() {
            var selectData = viewModel;
            var headHtm = ['<div class="' + Klass.header + '">', '<a href="javascript:void(0);" class="' + Klass.cancel + '">' + cancelText + '</a>', '<span class="tip">' + title + '</span>', '<a href="javascript:void(0);" class="' + Klass.confirm + '">' + confirmText + '</a>', '</div>'].join('');
            var bodyHtm = '<div class="' + Klass.wrapper + '"></div>';
            this.element.innerHTML = '' + '<div class="' + Klass.innerBox + '">' + headHtm + bodyHtm + '</div>';
            for (var key in selectData) {
                this.renderColumn(key, selectData[key]);
            }
            // 刷新
            this.refresh();
        }
        ;
        // 选择数据集
        this.selectedIndex = {};
        this.renderColumn = function(key, dataList) {
            var that = this;
            if (Array.isArray(dataList)) {
                var selectDomHtm = [];
                // 默认选中是第一个
                that.selectedIndex[key] = 0;
                dataList.forEach(function(item, index) {
                    if (item.selected) {
                        that.selectedIndex[key] = index;
                    }
                    selectDomHtm.push('<div class="' + Klass.option + '" data-value="' + item.value + '">' + item.key + '</div>');
                });
                var selectHTML = selectDomHtm.join('');
                var parentNode = that.element.querySelector('.' + Klass.wrapper);
                var oldEl = parentNode.querySelector('[data-type=' + key + ']');
                if (oldEl) {
                    oldEl.firstChild.innerHTML = selectHTML;
                } else {
                    var columnHtml = '<div class="scroller">' + selectHTML + '</div>';
                    var colEl = document.createElement('div');
                    colEl.className = Klass.col;
                    colEl.setAttribute('data-type', key);
                    colEl.innerHTML = columnHtml;
                    parentNode.appendChild(colEl);
                }
            } else {
                throw ('select项数据列表必须是数组');
            }
        }
        ;
        // --- scroll 操作
        this.setScroll = function() {
            var that = this;
            var selects = [].slice.call(this.element.querySelectorAll('.' + Klass.col));
            selects.forEach(function(value) {
                var scrollElement = value.querySelector('.scroller');
                var scroll = lib.scroll({
                    scrollElement: scrollElement,
                    inertia: 'slow'
                }).init();
                scrollElement.addEventListener('click', function(e) {
                    var target = e.target;
                    if (target.className.indexOf(Klass.option) === 0) {
                        scroll.scrollToElement(target, true);
                    }
                }, false);
                scroll.addScrollendHandler(function() {
                    that.scrollEndHandler(scroll, value);
                });
                var type = value.getAttribute('data-type');
                // 初始化滚动位置
                that.scrollToNthChild(scroll, that.selectedIndex[type]);
                // 增加是否需要触发事件处理器flag, 默认 true
                scroll.handler = true;
                myScroll[type] = scroll;
            });
            // cache
            this.selects = selects;
            this.scrolls = myScroll;
        }
        ;
        // 暴露当前操作的列名
        this.currentColName = '';
        this.scrollEndHandler = function(scrollObj, container) {
            if (!scrollObj.handler) {
                // reset to true
                scrollObj.handler = true;
                return;
            }
            var scrollTop = scrollObj.getScrollTop();
            // 修正按一行一行滚动
            var scrolled = Math.round(scrollTop / this.height);
            scrollObj.handler = false;
            this.scrollToNthChild(scrollObj, scrolled, false);
            var type = container.getAttribute('data-type');
            this.currentColName = type;
            this.setSelectedStatus(type, Math.abs(scrolled));
            // 选中值
            this.execEvent('select', type);
        }
        ;
        this.setSelectedStatus = function(colName, selectedIndex) {
            var container = this.scrolls[colName].element;
            var options = container.querySelectorAll('.' + Klass.option);
            currentOptions[colName] = container.querySelector('.current');
            currentOptions[colName] && (currentOptions[colName].className = Klass.option);
            currentOptions[colName] = options[selectedIndex];
            currentOptions[colName].className = Klass.option + ' current';
            selectedValue['val-' + colName] = currentOptions[colName].getAttribute('data-value');
            selectedValue['key-' + colName] = currentOptions[colName].innerHTML;
            // public
            this.selectedValue = selectedValue;
            this.selectedIndex[colName] = selectedIndex;
        }
        ;
        // 调整选中状态
        this.resetScrollPos = function() {
            var that = this;
            this.selects && this.selects.forEach(function(value) {
                var type = value.getAttribute('data-type');
                var scroll = that.scrolls[type];
                that.scrollToNthChild(scroll, that.selectedIndex[type]);
            })
        }
        ;
        // 滚动到某个元素
        this.scrollToNthChild = function(scroll, index, smooth) {
            var el = scroll.element;
            var target = el.querySelector(':nth-child(' + (1 + index) + ')');
            var isSmooth = typeof smooth != 'undefined' ? smooth : true;
            scroll.scrollToElement(target, isSmooth);
        }
        ;
        // -- 事件监听
        var scrollHasSet = false;
        var inited = false;
        this.addEvents = function() {
            var opts = this.options;
            var that = this;
            if (!inited) {
                // 兼容tbm：同步 tbm resize 监听 resize
                var timeout;
                function resize() {
                    that.refresh();
                }
                window.addEventListener('resize', function() {
                    clearTimeout(timeout);
                    timeout = setTimeout(resize, 310);
                }, false);
                if (opts.trigger) {
                    var triggers = opts.trigger.length > 1 ? [].slice.call(opts.trigger) : [opts.trigger];
                    triggers.forEach(function(value) {
                        value.addEventListener('click', function() {
                            // cache 触发器
                            that.trigger = value;
                            that.show();
                        });
                    });
                }
                inited = true;
            }
            // 确定
            this.element.querySelector('.' + Klass.confirm).addEventListener('click', function() {
                if (opts.verifyMe) {
                    if (opts.verifyMe(that.selectedValue)) {
                        that.hide();
                    } else {
                        return;
                    }
                } else {
                    that.hide();
                }
                // confirm select
                that.execEvent('confirm', that.trigger);
            }, false);
            // 取消
            this.element.querySelector('.' + Klass.cancel).addEventListener('click', function() {
                // cancel select
                that.execEvent('cancel', that.trigger);
                that.hide();
            }, false);
        }
        ;
        // --  接口方法
        this.show = function() {
            var that = this;
            // 展示之前
            this.execEvent('beforeShow', that.trigger);
            SelectBox.open(this.element);
            // 设置scroll
            setTimeout(function() {
                if (!scrollHasSet) {
                    that.setScroll();
                    scrollHasSet = true;
                }
            }, 100);
            this.execEvent('show');
        }
        ;
        this.hide = function() {
            SelectBox.close(this.element);
            this.execEvent('hide');
        }
        ;
        // 当窗口 resize 时调用
        this.refresh = function() {
            // fix 浮出窗口跑顶上去了
            this.element.style.height = window.innerHeight + 'px';
            var that = this;
            var getHeightInterval = setInterval(function() {
                var optionClass = '.' + Klass.option;
                var el = document.querySelector(optionClass);
                if (el && el.clientHeight) {
                    that.height = el.clientHeight;
                    that.resetScrollPos();
                    clearInterval(getHeightInterval);
                    getHeightInterval = null;
                }
            }, 100);
        }
        ;
        // 触发联动
        this.linkage = function(colName, colData) {
            this.viewModel[colName] = colData;
            this.renderColumn(colName, colData);
            // refresh scroll
            var scroll = this.scrolls[colName];
            var selectedIndex = this.selectedIndex[colName];
            scroll.refresh();
            this.scrollToNthChild(scroll, selectedIndex);
        }
        // 滚动选择值
        this.scrollToIndex = function(colName, index) {
            var scroll = this.scrolls[colName];
            this.scrollToNthChild(scroll, index);
            this.setSelectedStatus(colName, index);
        }
        ;
    };
    // export
    ctrl.selectmenu = SelectMenu;
})(window, window['ctrl'] || (window['ctrl'] = {}));
!function(a, b) {
    var c = a.location.hostname
      , d = /.*?([^.]+)(?:\.x)?\.(taobao|tmall|etao|alibaba|alipay|aliyun)\.(com|net).*/i
      , e = a.location.hostname.match(d)
      , f = c.match(/taobao\.net$/i) ? "waptest" : "m";
    !e || "waptest" !== e[1] && "wapa" !== e[1] && "m" !== e[1] || (f = e[1]),
    b.config = {
        hostReg: d,
        sysType: f,
        defaultAppKey: "waptest" === f ? "4272" : "12574478"
    }
}(window, window.lib || (window.lib = {})),
function(a, b) {
    var c = {}
      , d = b.config
      , e = {
        protocol: "http://",
        sysType: d.sysType,
        defaultDomain: "taobao.com"
    }
      , f = function(a) {
        try {
            return decodeURIComponent(a)
        } catch (b) {
            return a
        }
    }
      , g = c.getParam = function(a) {
        var b, c = this.queryMap || function(a) {
            if (a.length < 1)
                return "";
            a = a.substr(1);
            var b, c, d = a.split("&"), e = {};
            for (c in d)
                b = d[c].split("="),
                e[f(b[0])] = f(b[1]);
            return e
        }(location.search);
        return this.queryMap = c,
        a ? (b = c[a],
        b && b.indexOf("#") > -1 && (b = encodeURIComponent(b)),
        b) : c
    }
      , h = function(a) {
        var b, c, d, e = "";
        for (b in a)
            c = a[b],
            d = g(c),
            d && "" !== d && (e += "&" + c + "=" + d);
        return e
    }(["ttid", "sprefer"]);
    c.getUrl = function(a) {
        function b(a, b) {
            if (!b)
                return a;
            a.indexOf("?") < 0 && (a += "?");
            var c = a.charAt(a.length - 1)
              , d = b.charAt(0);
            return "?" === c || "&" === c ? "?" === d || "&" === d ? a + b.substr(1) : a + b : "?" === d || "&" === d ? a + b : a + "&" + b
        }
        var c = a.url || function(b) {
            var c = a.host || a.subdomain + "." + b.sysType + "." + b.defaultDomain;
            return b.protocol + c + "/" + a.path
        }(e);
        return c.indexOf("?") > 0 || (c += "?"),
        c = b(c, h),
        a.data && (c = b(c, function(a) {
            var b, c, d = "";
            if (null == a)
                return d;
            for (b in a)
                c = a[b],
                null != c && "" !== c && (d += b + "=" + encodeURIComponent("object" == typeof c ? JSON.stringify(c) : c) + "&");
            return "" !== d && d.length - 1 === d.lastIndexOf("&") && (d = d.substr(0, d.length - 1)),
            d
        }(a.data))),
        c
    }
    ,
    b.uri = c
}(window, window.lib || (window.lib = {}));
!function(a) {
    function b(a) {
        var b, c, d, e = "", f = 0;
        for (b = c = d = 0; f < a.length; )
            b = a.charCodeAt(f),
            128 > b ? (e += String.fromCharCode(b),
            f++) : b > 191 && 224 > b ? (d = a.charCodeAt(f + 1),
            e += String.fromCharCode((31 & b) << 6 | 63 & d),
            f += 2) : (d = a.charCodeAt(f + 1),
            c = a.charCodeAt(f + 2),
            e += String.fromCharCode((15 & b) << 12 | (63 & d) << 6 | 63 & c),
            f += 3);
        return e
    }
    function c(a) {
        a = a.replace(/\r\n/g, "\n");
        for (var b = "", c = 0; c < a.length; c++) {
            var d = a.charCodeAt(c);
            128 > d ? b += String.fromCharCode(d) : d > 127 && 2048 > d ? (b += String.fromCharCode(192 | d >> 6),
            b += String.fromCharCode(128 | 63 & d)) : (b += String.fromCharCode(224 | d >> 12),
            b += String.fromCharCode(128 | 63 & d >> 6),
            b += String.fromCharCode(128 | 63 & d))
        }
        return b
    }
    var d = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
    a.encode || (a.encode = {}),
    a.encode.base64_utf8 = {
        encode: function(a) {
            var b, e, f, g, h, i, j, k = "", l = 0;
            for (a = c(a); l < a.length; )
                b = a.charCodeAt(l++),
                e = a.charCodeAt(l++),
                f = a.charCodeAt(l++),
                g = b >> 2,
                h = (3 & b) << 4 | e >> 4,
                i = (15 & e) << 2 | f >> 6,
                j = 63 & f,
                isNaN(e) ? i = j = 64 : isNaN(f) && (j = 64),
                k = k + d.charAt(g) + d.charAt(h) + d.charAt(i) + d.charAt(j);
            return k
        },
        decode: function(a) {
            var c, e, f, g, h, i, j, k = "", l = 0;
            for (a = a.replace(/[^A-Za-z0-9\+\/\=]/g, ""); l < a.length; )
                g = d.indexOf(a.charAt(l++)),
                h = d.indexOf(a.charAt(l++)),
                i = d.indexOf(a.charAt(l++)),
                j = d.indexOf(a.charAt(l++)),
                c = g << 2 | h >> 4,
                e = (15 & h) << 4 | i >> 2,
                f = (3 & i) << 6 | j,
                k += String.fromCharCode(c),
                64 !== i && (k += String.fromCharCode(e)),
                64 !== j && (k += String.fromCharCode(f));
            return k = b(k)
        }
    }
}(window.lib || (window.lib = {}));
!function(a, b) {
    function c(a, b) {
        return [[(a / 3 + (a + b) / 3 - a) / (b - a), (a * a / 3 + a * b * 2 / 3 - a * a) / (b * b - a * a)], [(b / 3 + (a + b) / 3 - a) / (b - a), (b * b / 3 + a * b * 2 / 3 - a * a) / (b * b - a * a)]]
    }
    function d(a) {
        if (this.v = a.v || 0,
        this.a = a.a || 0,
        "undefined" != typeof a.t && (this.t = a.t),
        "undefined" != typeof a.s && (this.s = a.s),
        "undefined" == typeof this.t)
            if ("undefined" == typeof this.s)
                this.t = -this.v / this.a;
            else {
                var b = (Math.sqrt(this.v * this.v + 2 * this.a * this.s) - this.v) / this.a
                  , c = (-Math.sqrt(this.v * this.v + 2 * this.a * this.s) - this.v) / this.a;
                this.t = Math.min(b, c)
            }
        "undefined" == typeof this.s && (this.s = this.a * this.t * this.t / 2 + this.v * this.t)
    }
    d.prototype.generateCubicBezier = function() {
        return c(this.v / this.a, this.t + this.v / this.a)
    }
    ,
    b.motion = function(a) {
        return new d(a)
    }
}(window, window.lib || (window.lib = {}));
!function(a) {
    "use strict";
    function b(a, b) {
        for (var c = a; c; ) {
            if (c.contains(b) || c == b)
                return c;
            c = c.parentNode
        }
        return null
    }
    function c(a, b, c) {
        var d = i.createEvent("HTMLEvents");
        if (d.initEvent(b, !0, !0),
        "object" == typeof c)
            for (var e in c)
                d[e] = c[e];
        a.dispatchEvent(d)
    }
    function d(a, b, c, d, e, f, g, h) {
        var i = Math.atan2(h - f, g - e) - Math.atan2(d - b, c - a)
          , j = Math.sqrt((Math.pow(h - f, 2) + Math.pow(g - e, 2)) / (Math.pow(d - b, 2) + Math.pow(c - a, 2)))
          , k = [e - j * a * Math.cos(i) + j * b * Math.sin(i), f - j * b * Math.cos(i) - j * a * Math.sin(i)];
        return {
            rotate: i,
            scale: j,
            translate: k,
            matrix: [[j * Math.cos(i), -j * Math.sin(i), k[0]], [j * Math.sin(i), j * Math.cos(i), k[1]], [0, 0, 1]]
        }
    }
    function e(a) {
        0 === Object.keys(l).length && (j.addEventListener("touchmove", f, !1),
        j.addEventListener("touchend", g, !1),
        j.addEventListener("touchcancel", h, !1));
        for (var d = 0; d < a.changedTouches.length; d++) {
            var e = a.changedTouches[d]
              , i = {};
            for (var m in e)
                i[m] = e[m];
            var n = {
                startTouch: i,
                startTime: Date.now(),
                status: "tapping",
                element: a.srcElement || a.target,
                pressingHandler: setTimeout(function(b) {
                    return function() {
                        "tapping" === n.status && (n.status = "pressing",
                        c(b, "press", {
                            touchEvent: a
                        })),
                        clearTimeout(n.pressingHandler),
                        n.pressingHandler = null
                    }
                }(a.srcElement || a.target), 500)
            };
            l[e.identifier] = n
        }
        if (2 == Object.keys(l).length) {
            var o = [];
            for (var m in l)
                o.push(l[m].element);
            c(b(o[0], o[1]), "dualtouchstart", {
                touches: k.call(a.touches),
                touchEvent: a
            })
        }
    }
    function f(a) {
        for (var e = 0; e < a.changedTouches.length; e++) {
            var f = a.changedTouches[e]
              , g = l[f.identifier];
            if (!g)
                return;
            g.lastTouch || (g.lastTouch = g.startTouch),
            g.lastTime || (g.lastTime = g.startTime),
            g.velocityX || (g.velocityX = 0),
            g.velocityY || (g.velocityY = 0),
            g.duration || (g.duration = 0);
            var h = Date.now() - g.lastTime
              , i = (f.clientX - g.lastTouch.clientX) / h
              , j = (f.clientY - g.lastTouch.clientY) / h
              , k = 70;
            h > k && (h = k),
            g.duration + h > k && (g.duration = k - h),
            g.velocityX = (g.velocityX * g.duration + i * h) / (g.duration + h),
            g.velocityY = (g.velocityY * g.duration + j * h) / (g.duration + h),
            g.duration += h,
            g.lastTouch = {};
            for (var m in f)
                g.lastTouch[m] = f[m];
            g.lastTime = Date.now();
            var n = f.clientX - g.startTouch.clientX
              , o = f.clientY - g.startTouch.clientY
              , p = Math.sqrt(Math.pow(n, 2) + Math.pow(o, 2));
            ("tapping" === g.status || "pressing" === g.status) && p > 10 && (g.status = "panning",
            g.isVertical = !(Math.abs(n) > Math.abs(o)),
            c(g.element, "panstart", {
                touch: f,
                touchEvent: a,
                isVertical: g.isVertical
            }),
            c(g.element, (g.isVertical ? "vertical" : "horizontal") + "panstart", {
                touch: f,
                touchEvent: a
            })),
            "panning" === g.status && (g.panTime = Date.now(),
            c(g.element, "pan", {
                displacementX: n,
                displacementY: o,
                touch: f,
                touchEvent: a,
                isVertical: g.isVertical
            }),
            g.isVertical ? c(g.element, "verticalpan", {
                displacementY: o,
                touch: f,
                touchEvent: a
            }) : c(g.element, "horizontalpan", {
                displacementX: n,
                touch: f,
                touchEvent: a
            }))
        }
        if (2 == Object.keys(l).length) {
            for (var q, r = [], s = [], t = [], e = 0; e < a.touches.length; e++) {
                var f = a.touches[e]
                  , g = l[f.identifier];
                r.push([g.startTouch.clientX, g.startTouch.clientY]),
                s.push([f.clientX, f.clientY])
            }
            for (var m in l)
                t.push(l[m].element);
            q = d(r[0][0], r[0][1], r[1][0], r[1][1], s[0][0], s[0][1], s[1][0], s[1][1]),
            c(b(t[0], t[1]), "dualtouch", {
                transform: q,
                touches: a.touches,
                touchEvent: a
            })
        }
    }
    function g(a) {
        if (2 == Object.keys(l).length) {
            var d = [];
            for (var e in l)
                d.push(l[e].element);
            c(b(d[0], d[1]), "dualtouchend", {
                touches: k.call(a.touches),
                touchEvent: a
            })
        }
        for (var i = 0; i < a.changedTouches.length; i++) {
            var n = a.changedTouches[i]
              , o = n.identifier
              , p = l[o];
            if (p) {
                if (p.pressingHandler && (clearTimeout(p.pressingHandler),
                p.pressingHandler = null),
                "tapping" === p.status && (p.timestamp = Date.now(),
                c(p.element, "tap", {
                    touch: n,
                    touchEvent: a
                }),
                m && p.timestamp - m.timestamp < 300 && c(p.element, "doubletap", {
                    touch: n,
                    touchEvent: a
                }),
                m = p),
                "panning" === p.status) {
                    var q = Date.now()
                      , r = q - p.startTime
                      , s = ((n.clientX - p.startTouch.clientX) / r,
                    (n.clientY - p.startTouch.clientY) / r,
                    n.clientX - p.startTouch.clientX)
                      , t = n.clientY - p.startTouch.clientY
                      , u = Math.sqrt(p.velocityY * p.velocityY + p.velocityX * p.velocityX)
                      , v = u > .5 && q - p.lastTime < 100
                      , w = {
                        duration: r,
                        isflick: v,
                        velocityX: p.velocityX,
                        velocityY: p.velocityY,
                        displacementX: s,
                        displacementY: t,
                        touch: n,
                        touchEvent: a,
                        isVertical: p.isVertical
                    };
                    c(p.element, "panend", w),
                    v && (c(p.element, "flick", w),
                    p.isVertical ? c(p.element, "verticalflick", w) : c(p.element, "horizontalflick", w))
                }
                "pressing" === p.status && c(p.element, "pressend", {
                    touch: n,
                    touchEvent: a
                }),
                delete l[o]
            }
        }
        0 === Object.keys(l).length && (j.removeEventListener("touchmove", f, !1),
        j.removeEventListener("touchend", g, !1),
        j.removeEventListener("touchcancel", h, !1))
    }
    function h(a) {
        if (2 == Object.keys(l).length) {
            var d = [];
            for (var e in l)
                d.push(l[e].element);
            c(b(d[0], d[1]), "dualtouchend", {
                touches: k.call(a.touches),
                touchEvent: a
            })
        }
        for (var i = 0; i < a.changedTouches.length; i++) {
            var m = a.changedTouches[i]
              , n = m.identifier
              , o = l[n];
            o && (o.pressingHandler && (clearTimeout(o.pressingHandler),
            o.pressingHandler = null),
            "panning" === o.status && c(o.element, "panend", {
                touch: m,
                touchEvent: a
            }),
            "pressing" === o.status && c(o.element, "pressend", {
                touch: m,
                touchEvent: a
            }),
            delete l[n])
        }
        0 === Object.keys(l).length && (j.removeEventListener("touchmove", f, !1),
        j.removeEventListener("touchend", g, !1),
        j.removeEventListener("touchcancel", h, !1))
    }
    var i = a.document
      , j = i.documentElement
      , k = Array.prototype.slice
      , l = {}
      , m = null;
    j.addEventListener("touchstart", e, !1)
}(window, window.lib || (window.lib = {}));
!function(a, b) {
    function c(a, b, c, d) {
        function e(a) {
            return (3 * k * a + 2 * l) * a + m
        }
        function f(a) {
            return ((k * a + l) * a + m) * a
        }
        function g(a) {
            return ((n * a + o) * a + p) * a
        }
        function h(a) {
            for (var b, c, d = a, g = 0; 8 > g; g++) {
                if (c = f(d) - a,
                Math.abs(c) < j)
                    return d;
                if (b = e(d),
                Math.abs(b) < j)
                    break;
                d -= c / b
            }
            var h = 1
              , i = 0;
            for (d = a; h > i; ) {
                if (c = f(d) - a,
                Math.abs(c) < j)
                    return d;
                c > 0 ? h = d : i = d,
                d = (h + i) / 2
            }
            return d
        }
        function i(a) {
            return g(h(a))
        }
        var j = 1e-6
          , k = 3 * a - 3 * c + 1
          , l = 3 * c - 6 * a
          , m = 3 * a
          , n = 3 * b - 3 * d + 1
          , o = 3 * d - 6 * b
          , p = 3 * b;
        return i
    }
    b.cubicbezier = c,
    b.cubicbezier.linear = c(0, 0, 1, 1),
    b.cubicbezier.ease = c(.25, .1, .25, 1),
    b.cubicbezier.easeIn = c(.42, 0, 1, 1),
    b.cubicbezier.easeOut = c(0, 0, .58, 1),
    b.cubicbezier.easeInOut = c(.42, 0, .58, 1)
}(window, window.lib || (window.lib = {}));
;(function(win, ctrl) {
    var Promise = win.Promise;
    var isIEMobile = win.navigator.userAgent.match(/IEMobile\/([\d\.]+)/);
    var stylePrefix = !!isIEMobile ? 'ms' : 'webkit';
    var incId = 0;
    /**
     * 初始化加载动画实例
     * @class ctrl.loading~Loading
     * @param {HTMLElement} [element] - 初始化的元素，可省略
     */
    function Loading(element, options) {
        var that = this;
        var id = Date.now() + '-' + (++incId);
        var root = document.createDocumentFragment();
        if (arguments.length === 1 && !(arguments[0]instanceof HTMLElement)) {
            options = arguments[0];
            element = null;
        }
        if (!element) {
            element = document.createElement('div');
            root.appendChild(element);
        }
        options = options || {};
        element.setAttribute('data-ctrl-name', 'loading');
        element.setAttribute('data-ctrl-id', id);
        element.innerHTML = '<div rol="draw">' + '<canvas></canvas><span class="arrow"></span>' + '</div>' + '<div rol="spin">' + '<div class="circle"><span></span></div>' + '</div>' + '<span class="text"></span>';
        var canvas, context, radius, lineWidth, startAngle, perAngle, isInitCanvas = false;
        var canvasPixelRatio = 2;
        function initCanvas() {
            if (!isInitCanvas) {
                isInitCanvas = true;
                canvas = element.querySelector('canvas');
                context = canvas.getContext('2d');
                startAngle = 0.13373158940994154;
                perAngle = 0.06015722128359704;
            }
            var rect = canvas.getBoundingClientRect();
            if (canvas.width !== rect.width * canvasPixelRatio || canvas.height !== rect.height * canvasPixelRatio) {
                canvas.width = rect.width * canvasPixelRatio;
                canvas.height = rect.height * canvasPixelRatio;
                radius = rect.width / 2;
                lineWidth = radius / 15;
            }
        }
        var drawEl = element.querySelector('[rol="draw"]');
        var spinEl = element.querySelector('[rol="spin"]');
        function draw(per) {
            if (mode !== 'draw')
                return;
            initCanvas();
            spinEl.style.display = 'none';
            drawEl.style.display = 'block';
            if (per > 100) {
                per = 100;
            }
            context.clearRect(0, 0, canvas.width * canvasPixelRatio, canvas.height * canvasPixelRatio);
            context.beginPath();
            context.arc(radius * canvasPixelRatio, radius * canvasPixelRatio, (radius - lineWidth) * canvasPixelRatio, -startAngle - Math.PI / 2, -startAngle - Math.PI / 2 - perAngle * per, true);
            context.lineWidth = lineWidth * canvasPixelRatio;
            context.strokeStyle = '#999';
            context.stroke();
            context.closePath();
        }
        function spin() {
            if (mode !== 'spin')
                return;
            spinEl.style.display = 'block';
            drawEl.style.display = 'none';
        }
        function showArrow() {
            var arrow = element.querySelector('.arrow');
            arrow.style.cssText = 'display: block';
            return Promise.resolve();
        }
        function hideArrow() {
            var arrow = element.querySelector('.arrow');
            // arrow.style.cssText = 'display: none';
            arrow.style[stylePrefix + 'Transform'] = 'scale(1)';
            arrow.style.opacity = '1';
            return new lib.animation(400,lib.cubicbezier.easeIn,function(i1, i2) {
                arrow.style[stylePrefix + 'Transform'] = 'scale(' + (1 - 0.5 * i2) + ')';
                arrow.style.opacity = (1 - i2) + '';
            }
            ).play().then(function() {
                arrow.style.cssText = 'display:none';
            });
        }
        /**
         * 获取/设置背景色
         * @member {String} bgcolor
         * @memberof ctrl.loading~Loading
         * @instance
         */
        Object.defineProperty(this, 'bgcolor', {
            get: function() {
                return element.style.backgroundColor;
            },
            set: function(v) {
                if (typeof v !== 'string') {
                    throw new Error('Non expected value');
                } else {
                    element.querySelector('[rol="spin"] span').style.backgroundColor = v;
                    element.style.backgroundColor = v;
                }
            }
        });
        /**
         * 获取/设置文本
         * @member {String} text
         * @memberof ctrl.loading~Loading
         * @instance
         */
        Object.defineProperty(this, 'text', {
            get: function() {
                return element.querySelector('.text').textContent;
            },
            set: function(v) {
                if (typeof v !== 'string') {
                    throw new Error('Non expected value');
                } else {
                    var divEl = element.querySelector('div');
                    var textEl = element.querySelector('.text');
                    if (v) {
                        element.style[stylePrefix + 'BoxPack'] = '';
                        divEl.style.marginLeft = '';
                        textEl.style.display = 'block';
                        textEl.textContent = v;
                    } else {
                        element.style[stylePrefix + 'BoxPack'] = 'center';
                        divEl.style.marginLeft = '0';
                        textEl.style.display = 'none';
                        textEl.textContent = '';
                    }
                }
            }
        });
        /**
         * 获取/设置模式，draw 绘制模式，可设置绘制的百分比；spin 旋转模式
         * @member {String} mode
         * @memberof ctrl.loading~Loading
         * @instance
         */
        var mode = '';
        Object.defineProperty(this, 'mode', {
            get: function() {
                return mode;
            },
            set: function(v) {
                if (!v && typeof v !== 'string' && ['draw', 'spin'].indexOf(v) < 0) {
                    throw new Error('Non expected value');
                } else {
                    mode = v;
                    if (mode === 'spin') {
                        if (arrowDirection) {
                            hideArrow().then(spin);
                        } else {
                            spin();
                        }
                    } else if (mode === 'draw') {
                        showArrow().then(function() {
                            draw(0);
                        });
                    }
                }
            }
        });
        /**
         * 获取/设置绘制的百分比，在绘制模式下设置百分比0~100
         * @member {String} per
         * @memberof ctrl.loading~Loading
         * @instance
         */
        var per = 0;
        Object.defineProperty(this, 'per', {
            get: function() {
                return per;
            },
            set: function(v) {
                if (mode !== 'draw') {
                    throw new Error('only work under "draw" mode');
                }
                if (!v && typeof v !== 'number' && v < 0 && v > 100) {
                    throw new Error('Non expected value');
                } else {
                    draw(v);
                }
            }
        });
        /**
         * 获取/设置箭头的方向
         * @member {String} arrowDirection
         * @memberof ctrl.loading~Loading
         * @instance
         */
        var arrowDirection = '';
        Object.defineProperty(this, 'arrowDirection', {
            get: function() {
                return arrowDirection;
            },
            set: function(v) {
                if (!v && typeof v !== 'string' && ['up', 'down', ''].indexOf(v) < 0) {
                    throw new Error('Non expected value');
                } else {
                    arrowDirection = v;
                    element.querySelector('.arrow').className = 'arrow ' + v;
                }
            }
        });
        /**
         * 移除控件
         * @method remove
         * @memberof ctrl.loading~Loading
         * @instance
         */
        this.remove = function() {
            if (element.parentNode) {
                element.parentNode.removeChild(element);
            }
        }
        this.element = element;
        /**
         * 当前控件的根元素
         * @member {HTMLElment} root
         * @memberof ctrl.loading~Loading
         * @instance
         */
        this.root = root;
    }
    /**
     * @namespace ctrl
     */
    /**
     * 生成加载动画控件实例
     * @method loading
     * @param {HTMLElement} element - 初始化的元素，可省略
     * @return {ctrl.loading~Loading} Loading实例
     * @memberof ctrl
     */
    ctrl.loading = function(element) {
        return new Loading(element);
    }
})(window, window['ctrl'] || (window['ctrl'] = {}));
!function(a, b) {
    function c(a) {
        return setTimeout(a, l)
    }
    function d(a) {
        clearTimeout(a)
    }
    function e() {
        var a = {}
          , b = new m(function(b, c) {
            a.resolve = b,
            a.reject = c
        }
        );
        return a.promise = b,
        a
    }
    function f(a, b) {
        return ["then", "catch"].forEach(function(c) {
            b[c] = function() {
                return a[c].apply(a, arguments)
            }
        }),
        b
    }
    function g(b) {
        var c, d, h = !1;
        this.request = function() {
            h = !1;
            var g = arguments;
            return c = e(),
            f(c.promise, this),
            d = n(function() {
                h || c && c.resolve(b.apply(a, g))
            }),
            this
        }
        ,
        this.cancel = function() {
            return d && (h = !0,
            o(d),
            c && c.reject("CANCEL")),
            this
        }
        ,
        this.clone = function() {
            return new g(b)
        }
    }
    function h(a, b) {
        "function" == typeof b && (b = {
            0: b
        });
        for (var c = a / l, d = 1 / c, e = [], f = Object.keys(b).map(function(a) {
            return parseInt(a)
        }), h = 0; c > h; h++) {
            var i = f[0]
              , j = d * h;
            if (null != i && 100 * j >= i) {
                var k = b["" + i];
                k instanceof g || (k = new g(k)),
                e.push(k),
                f.shift()
            } else
                e.length && e.push(e[e.length - 1].clone())
        }
        return e
    }
    function i(a) {
        var c;
        return "string" == typeof a || a instanceof Array ? b.cubicbezier ? "string" == typeof a ? b.cubicbezier[a] && (c = b.cubicbezier[a]) : a instanceof Array && 4 === a.length && (c = b.cubicbezier.apply(b.cubicbezier, a)) : console.error("require lib.cubicbezier") : "function" == typeof a && (c = a),
        c
    }
    function j(a, b, c) {
        var d, g = h(a, c), j = 1 / (a / l), k = 0, m = i(b);
        if (!m)
            throw new Error("unexcept timing function");
        var n = !1;
        this.play = function() {
            function a() {
                var c = j * (k + 1).toFixed(10)
                  , e = g[k];
                e.request(c.toFixed(10), b(c).toFixed(10)).then(function() {
                    n && (k === g.length - 1 ? (n = !1,
                    d && d.resolve("FINISH"),
                    d = null) : (k++,
                    a()))
                }, function() {})
            }
            if (!n)
                return n = !0,
                d || (d = e(),
                f(d.promise, this)),
                a(),
                this
        }
        ,
        this.stop = function() {
            return n ? (n = !1,
            g[k] && g[k].cancel(),
            this) : void 0
        }
    }
    var k = 60
      , l = 1e3 / k
      , m = a.Promise || b.promise && b.promise.ES6Promise
      , n = window.requestAnimationFrame || window.msRequestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || c
      , o = window.cancelAnimationFrame || window.msCancelAnimationFrame || window.webkitCancelAnimationFrame || window.mozCancelAnimationFrame || d;
    (n === c || o === d) && (n = c,
    o = d),
    b.animation = function(a, b, c) {
        return new j(a,b,c)
    }
    ,
    b.animation.frame = function(a) {
        return new g(a)
    }
    ,
    b.animation.requestFrame = function(a) {
        var b = new g(a);
        return b.request()
    }
}(window, window.lib || (window.lib = {}));
;(function(win, lib, undef) {
    var doc = win.document;
    var ua = win.navigator.userAgent;
    var scrollObjs = {};
    var plugins = {};
    var dpr = win.dpr || (!!win.navigator.userAgent.match(/iPhone|iPad|iPod/) ? document.documentElement.clientWidth / win.screen.availWidth : 1);
    var inertiaCoefficient = {
        'normal': [2 * dpr, 0.0015 * dpr],
        'slow': [1.5 * dpr, 0.003 * dpr],
        'veryslow': [1.5 * dpr, 0.005 * dpr]
    }
    var timeFunction = {
        'ease': [.25, .1, .25, 1],
        'liner': [0, 0, 1, 1],
        'ease-in': [.42, 0, 1, 1],
        'ease-out': [0, 0, .58, 1],
        'ease-in-out': [.42, 0, .58, 1]
    }
    var Firefox = !!ua.match(/Firefox/i);
    var IEMobile = !!ua.match(/IEMobile/i);
    var cssPrefix = Firefox ? '-moz-' : IEMobile ? '-ms-' : '-webkit-';
    var stylePrefix = Firefox ? 'Moz' : IEMobile ? 'ms' : 'webkit';
    function debugLog() {
        if (lib.scroll.outputDebugLog) {
            console.debug.apply(console, arguments);
        }
    }
    function getBoundingClientRect(el) {
        var rect = el.getBoundingClientRect();
        if (!rect) {
            rect = {};
            rect.width = el.offsetWidth;
            rect.height = el.offsetHeight;
            rect.left = el.offsetLeft;
            rect.top = el.offsetTop;
            var parent = el.offsetParent;
            while (parent) {
                rect.left += parent.offsetLeft;
                rect.top += parent.offsetTop;
                parent = parent.offsetParent;
            }
            rect.right = rect.left + rect.width;
            rect.bottom = rect.top + rect.height;
        }
        return rect;
    }
    function getMinScrollOffset(scrollObj) {
        return 0 - scrollObj.options[scrollObj.axis + 'PaddingTop'];
    }
    function getMaxScrollOffset(scrollObj) {
        var rect = getBoundingClientRect(scrollObj.element);
        var pRect = getBoundingClientRect(scrollObj.viewport);
        var min = getMinScrollOffset(scrollObj);
        if (scrollObj.axis === 'y') {
            var max = 0 - rect.height + pRect.height;
        } else {
            var max = 0 - rect.width + pRect.width;
        }
        return Math.min(max + scrollObj.options[scrollObj.axis + 'PaddingBottom'], min);
    }
    function getBoundaryOffset(scrollObj, offset) {
        if (offset > scrollObj.minScrollOffset) {
            return offset - scrollObj.minScrollOffset;
        } else if (offset < scrollObj.maxScrollOffset) {
            return offset - scrollObj.maxScrollOffset;
        }
    }
    function touchBoundary(scrollObj, offset) {
        if (offset > scrollObj.minScrollOffset) {
            offset = scrollObj.minScrollOffset;
        } else if (offset < scrollObj.maxScrollOffset) {
            offset = scrollObj.maxScrollOffset;
        }
        return offset;
    }
    function fireEvent(scrollObj, eventName, extra) {
        debugLog(scrollObj.element.scrollId, eventName, extra);
        var event = doc.createEvent('HTMLEvents');
        event.initEvent(eventName, false, true);
        event.scrollObj = scrollObj;
        if (extra) {
            for (var key in extra) {
                event[key] = extra[key];
            }
        }
        scrollObj.element.dispatchEvent(event);
        scrollObj.viewport.dispatchEvent(event);
    }
    function getTransformOffset(scrollObj) {
        var offset = {
            x: 0,
            y: 0
        };
        var transform = getComputedStyle(scrollObj.element)[stylePrefix + 'Transform'];
        var matched;
        if (transform !== 'none') {
            if ((matched = transform.match(/^matrix3d\((?:[-\d.]+,\s*){12}([-\d.]+),\s*([-\d.]+)(?:,\s*[-\d.]+){2}\)/) || transform.match(/^matrix\((?:[-\d.]+,\s*){4}([-\d.]+),\s*([-\d.]+)\)$/)) ) {
                offset.x = parseFloat(matched[1]) || 0;
                offset.y = parseFloat(matched[2]) || 0;
            }
        }
        return offset;
    }
    var CSSMatrix = IEMobile ? 'MSCSSMatrix' : 'WebKitCSSMatrix';
    var has3d = !!Firefox || CSSMatrix in win && 'm11'in new win[CSSMatrix]();
    function getTranslate(x, y) {
        x = parseFloat(x);
        y = parseFloat(y);
        if (x != 0) {
            x += 'px';
        }
        if (y != 0) {
            y += 'px';
        }
        if (has3d) {
            return 'translate3d(' + x + ', ' + y + ', 0)';
        } else {
            return 'translate(' + x + ', ' + y + ')';
        }
    }
    function setTransitionStyle(scrollObj, duration, timingFunction) {
        if (duration === '' && timingFunction === '') {
            scrollObj.element.style[stylePrefix + 'Transition'] = '';
        } else {
            scrollObj.element.style[stylePrefix + 'Transition'] = cssPrefix + 'transform ' + duration + ' ' + timingFunction + ' 0s';
        }
    }
    function setTransformStyle(scrollObj, offset) {
        var x = 0
          , y = 0;
        if (typeof offset === 'object') {
            x = offset.x;
            y = offset.y;
        } else {
            if (scrollObj.axis === 'y') {
                y = offset;
            } else {
                x = offset;
            }
        }
        scrollObj.element.style[stylePrefix + 'Transform'] = getTranslate(x, y);
    }
    var panning = false;
    doc.addEventListener('touchmove', function(e) {
        if (panning) {
            e.preventDefault();
            return false;
        }
        return true;
    }, false);
    /**
 * @class lib.scroll~Scroll
 * @param  {HTMLElement} [element] 需要滚动的元素，可省略
 * @param  {Object} options 设置
 * @param  {HTMLElement} [options.scrollElement] 需要滚动的元素
 * @param  {HTMLElement} [options.scrollWrap] 需要滚动元素的父元素
 * @param  {String} [options.direction='y'] 滚动的方向，默认是“y”，即垂直滚动。如需水平滚动，就设置为“x”
 * @param  {HTMLElement} [options.downgrade=false] 是否降级，默认为false，如需降级，请设置为true，并引入downgrade.js
 * @param  {Boolean} [options.noBounce=false] 边缘是否回弹效果，默认为false
 * @param  {String} [options.inertia='normal'] 惯性的类型，可取值为normal，slow，veryslow
 * @param  {Boolean} [options.isPrevent=true] 阻止默认滚动，默认为true
 * @param  {Boolean} [options.isFixScrollendClick=true] 点停滚动时，触发点击事件的问题，默认为true
 * @param  {Boolean} [options.useFrameAnimation=false] 用帧动画实现滚动，默认为false
 * @return {lib.scroll~Scroll}         Scroll类实例
 */
    function Scroll(element, options) {
        var that = this;
        options = options || {};
        options.noBounce = !!options.noBounce;
        options.padding = options.padding || {};
        if (options.isPrevent == null) {
            options.isPrevent = true;
        } else {
            options.isPrevent = !!options.isPrevent;
        }
        if (options.isFixScrollendClick == null) {
            options.isFixScrollendClick = true;
        } else {
            options.isFixScrollendClick = !!options.isFixScrollendClick;
        }
        if (options.padding) {
            options.yPaddingTop = -options.padding.top || 0;
            options.yPaddingBottom = -options.padding.bottom || 0;
            options.xPaddingTop = -options.padding.left || 0;
            options.xPaddingBottom = -options.padding.right || 0;
        } else {
            options.yPaddingTop = 0;
            options.yPaddingBottom = 0;
            options.xPaddingTop = 0;
            options.xPaddingBottom = 0;
        }
        options.direction = options.direction || 'y';
        options.inertia = options.inertia || 'normal';
        this.options = options;
        that.axis = options.direction;
        this.element = element;
        this.viewport = element.parentNode;
        this.plugins = {};
        this.element.scrollId = setTimeout(function() {
            scrollObjs[that.element.scrollId + ''] = that;
        }, 1);
        this.viewport.addEventListener('touchstart', touchstartHandler, false);
        this.viewport.addEventListener('touchend', touchendHandler, false);
        this.viewport.addEventListener('touchcancel', touchendHandler, false);
        this.viewport.addEventListener('panstart', panstartHandler, false);
        this.viewport.addEventListener('pan', panHandler, false);
        this.viewport.addEventListener('panend', panendHandler, false);
        if (options.isPrevent) {
            this.viewport.addEventListener('touchstart', function(e) {
                panning = true;
            }, false);
            that.viewport.addEventListener('touchend', function(e) {
                panning = false;
            }, false);
        }
        // if (options.isPrevent) {
        //     var d = this.axis === 'y'?'vertical':'horizontal';
        //     this.viewport.addEventListener(d + 'panstart', function(e) {
        //         panning = true;
        //     }, false);
        //     that.viewport.addEventListener('panend', function(e){
        //         panning = false;
        //     }, false);
        // }
        if (options.isFixScrollendClick) {
            var preventScrollendClick;
            var fixScrollendClickTimeoutId;
            this.viewport.addEventListener('scrolling', function() {
                preventScrollendClick = true;
                fixScrollendClickTimeoutId && clearTimeout(fixScrollendClickTimeoutId);
                fixScrollendClickTimeoutId = setTimeout(function(e) {
                    preventScrollendClick = false;
                }, 400);
            }, false);
            function preventScrollendClickHandler(e) {
                if (preventScrollendClick || isScrolling) {
                    e.preventDefault();
                    e.stopPropagation();
                    return false;
                } else {
                    return true;
                }
            }
            function fireNiceTapEventHandler(e) {
                if (!preventScrollendClick && !isScrolling) {
                    setTimeout(function() {
                        var niceTapEvent = document.createEvent('HTMLEvents');
                        niceTapEvent.initEvent('niceclick', true, true);
                        e.target.dispatchEvent(niceTapEvent);
                    }, 300);
                }
            }
            this.viewport.addEventListener('click', preventScrollendClickHandler, false);
            this.viewport.addEventListener('tap', fireNiceTapEventHandler, false);
        }
        if (options.useFrameAnimation) {
            var scrollAnimation;
            Object.defineProperty(this, 'animation', {
                get: function() {
                    return scrollAnimation;
                }
            });
        } else {
            var transitionEndHandler;
            var transitionEndTimeoutId = 0;
            function setTransitionEndHandler(h, t) {
                transitionEndHandler = null;
                clearTimeout(transitionEndTimeoutId);
                transitionEndTimeoutId = setTimeout(function() {
                    if (transitionEndHandler) {
                        transitionEndHandler = null;
                        lib.animation.requestFrame(h);
                    }
                }, (t || 400));
                transitionEndHandler = h;
            }
            element.addEventListener(Firefox ? 'transitionend' : (stylePrefix + 'TransitionEnd'), function(e) {
                if (transitionEndHandler) {
                    var handler = transitionEndHandler;
                    transitionEndHandler = null;
                    clearTimeout(transitionEndTimeoutId);
                    lib.animation.requestFrame(function() {
                        handler(e);
                    });
                }
            }, false);
        }
        var panFixRatio;
        var isScrolling;
        var isFlickScrolling;
        var cancelScrollEnd;
        Object.defineProperty(this, 'isScrolling', {
            get: function() {
                return !!isScrolling;
            }
        });
        function isEnabled(e) {
            if (!that.enabled) {
                return false;
            }
            if (typeof e.isVertical != 'undefined') {
                if (that.axis === 'y' && e.isVertical || that.axis === 'x' && !e.isVertical) {
                    // 同方向的手势，停止冒泡
                    e.stopPropagation();
                } else {
                    // 不是同方向的手势，冒泡到上层，不做任何处理
                    return false;
                }
            }
            return true;
        }
        function touchstartHandler(e) {
            if (!isEnabled(e)) {
                return;
            }
            if (isScrolling) {
                scrollEnd();
            }
            if (options.useFrameAnimation) {
                scrollAnimation && scrollAnimation.stop();
                scrollAnimation = null;
            } else {
                var transform = getTransformOffset(that);
                setTransformStyle(that, transform);
                setTransitionStyle(that, '', '');
                transitionEndHandler = null;
                clearTimeout(transitionEndTimeoutId);
            }
        }
        function touchendHandler(e) {
            if (!isEnabled(e)) {
                return;
            }
            var s0 = getTransformOffset(that)[that.axis];
            var boundaryOffset = getBoundaryOffset(that, s0);
            if (boundaryOffset) {
                // 拖动超出边缘，需要回弹
                var s1 = touchBoundary(that, s0);
                if (options.useFrameAnimation) {
                    // frame
                    var _s = s1 - s0;
                    scrollAnimation = new lib.animation(400,lib.cubicbezier.ease,function(i1, i2) {
                        var offset = (s0 + _s * i2).toFixed(2);
                        setTransformStyle(that, offset);
                        fireEvent(that, 'scrolling');
                    }
                    );
                    scrollAnimation.play().then(scrollEnd);
                } else {
                    // css
                    var offset = s1.toFixed(0);
                    setTransitionStyle(that, '0.4s', 'ease');
                    setTransformStyle(that, offset);
                    setTransitionEndHandler(scrollEnd, 400);
                    lib.animation.requestFrame(function() {
                        if (isScrolling && that.enabled) {
                            fireEvent(that, 'scrolling');
                            lib.animation.requestFrame(arguments.callee);
                        }
                    });
                }
                if (boundaryOffset > 0) {
                    fireEvent(that, that.axis === 'y' ? 'pulldownend' : 'pullrightend');
                } else if (boundaryOffset < 0) {
                    fireEvent(that, that.axis === 'y' ? 'pullupend' : 'pullleftend');
                }
            } else if (isScrolling) {
                // 未超出边缘，直接结束
                scrollEnd();
            }
        }
        var lastDisplacement;
        function panstartHandler(e) {
            if (!isEnabled(e)) {
                return;
            }
            that.transformOffset = getTransformOffset(that);
            that.minScrollOffset = getMinScrollOffset(that);
            that.maxScrollOffset = getMaxScrollOffset(that);
            panFixRatio = 2.5;
            cancelScrollEnd = true;
            isScrolling = true;
            isFlickScrolling = false;
            fireEvent(that, 'scrollstart');
            lastDisplacement = e['displacement' + that.axis.toUpperCase()];
        }
        function panHandler(e) {
            if (!isEnabled(e)) {
                return;
            }
            // 手指移动小于5像素，也忽略
            var displacement = e['displacement' + that.axis.toUpperCase()];
            if (Math.abs(displacement - lastDisplacement) < 5) {
                e.stopPropagation();
                return;
            }
            lastDisplacement = displacement;
            var offset = that.transformOffset[that.axis] + displacement;
            if (offset > that.minScrollOffset) {
                offset = that.minScrollOffset + (offset - that.minScrollOffset) / panFixRatio;
                panFixRatio *= 1.003;
            } else if (offset < that.maxScrollOffset) {
                offset = that.maxScrollOffset - (that.maxScrollOffset - offset) / panFixRatio;
                panFixRatio *= 1.003;
            }
            if (panFixRatio > 4) {
                panFixRatio = 4;
            }
            // 判断是否到了边缘
            var boundaryOffset = getBoundaryOffset(that, offset);
            if (boundaryOffset) {
                fireEvent(that, boundaryOffset > 0 ? (that.axis === 'y' ? 'pulldown' : 'pullright') : (that.axis === 'y' ? 'pullup' : 'pullleft'), {
                    boundaryOffset: Math.abs(boundaryOffset)
                });
                if (that.options.noBounce) {
                    offset = touchBoundary(that, offset);
                }
            }
            setTransformStyle(that, offset.toFixed(2));
            fireEvent(that, 'scrolling');
        }
        function panendHandler(e) {
            if (!isEnabled(e)) {
                return;
            }
            if (e.isflick) {
                flickHandler(e);
            }
        }
        function flickHandler(e) {
            cancelScrollEnd = true;
            var v0, a0, t0, s0, s, motion0;
            var v1, a1, t1, s1, motion1, sign;
            var v2, a2, t2, s2, motion2, ft;
            s0 = getTransformOffset(that)[that.axis];
            var boundaryOffset0 = getBoundaryOffset(that, s0);
            if (!boundaryOffset0) {
                //手指离开屏幕时，已经超出滚动范围，不作处理，让touchend handler处理
                //手指离开屏幕时，在滚动范围内，做一下惯性计算
                v0 = e['velocity' + that.axis.toUpperCase()];
                var maxV = 2;
                var friction = 0.0015;
                if (options.inertia && inertiaCoefficient[options.inertia]) {
                    maxV = inertiaCoefficient[options.inertia][0];
                    friction = inertiaCoefficient[options.inertia][1];
                }
                if (v0 > maxV) {
                    v0 = maxV;
                }
                if (v0 < -maxV) {
                    v0 = -maxV;
                }
                a0 = friction * (v0 / Math.abs(v0));
                motion0 = new lib.motion({
                    v: v0,
                    a: -a0
                });
                t0 = motion0.t;
                s = s0 + motion0.s;
                var boundaryOffset1 = getBoundaryOffset(that, s);
                if (boundaryOffset1) {
                    //惯性运动足够滑出屏幕边缘
                    debugLog('惯性计算超出了边缘', boundaryOffset1);
                    v1 = v0;
                    a1 = a0;
                    if (boundaryOffset1 > 0) {
                        s1 = that.minScrollOffset;
                        sign = 1;
                    } else {
                        s1 = that.maxScrollOffset;
                        sign = -1;
                    }
                    motion1 = new lib.motion({
                        v: sign * v1,
                        a: -sign * a1,
                        s: Math.abs(s1 - s0)
                    });
                    t1 = motion1.t;
                    var timeFunction1 = motion1.generateCubicBezier();
                    v2 = v1 - a1 * t1;
                    a2 = 0.03 * (v2 / Math.abs(v2));
                    motion2 = new lib.motion({
                        v: v2,
                        a: -a2
                    });
                    t2 = motion2.t;
                    s2 = s1 + motion2.s;
                    var timeFunction2 = motion2.generateCubicBezier();
                    if (options.noBounce) {
                        // 没有边缘回弹效果，直接平顺滑到边缘
                        debugLog('没有回弹效果');
                        if (s0 !== s1) {
                            if (options.useFrameAnimation) {
                                // frame
                                var _s = s1 - s0;
                                var bezier = lib.cubicbezier(timeFunction1[0][0], timeFunction1[0][1], timeFunction1[1][0], timeFunction1[1][1]);
                                scrollAnimation = new lib.animation(t1.toFixed(0),bezier,function(i1, i2) {
                                    var offset = (s0 + _s * i2);
                                    getTransformOffset(that, offset.toFixed(2));
                                    fireEvent(that, 'scrolling', {
                                        afterFlick: true
                                    });
                                }
                                );
                                scrollAnimation.play().then(scrollEnd);
                            } else {
                                // css
                                var offset = s1.toFixed(0);
                                setTransitionStyle(that, (t1 / 1000).toFixed(2) + 's', 'cubic-bezier(' + timeFunction1 + ')');
                                setTransformStyle(that, offset);
                                setTransitionEndHandler(scrollEnd, (t1 / 1000).toFixed(2) * 1000);
                            }
                        } else {
                            scrollEnd();
                        }
                    } else if (s0 !== s2) {
                        debugLog('惯性滚动', 's=' + s2.toFixed(0), 't=' + ((t1 + t2) / 1000).toFixed(2));
                        if (options.useFrameAnimation) {
                            var _s = s2 - s0;
                            var bezier = lib.cubicbezier.easeOut;
                            scrollAnimation = new lib.animation((t1 + t2).toFixed(0),bezier,function(i1, i2) {
                                var offset = s0 + _s * i2;
                                setTransformStyle(that, offset.toFixed(2));
                                fireEvent(that, 'scrolling', {
                                    afterFlick: true
                                });
                            }
                            );
                            scrollAnimation.play().then(function() {
                                if (!that.enabled) {
                                    return;
                                }
                                var _s = s1 - s2;
                                var bezier = lib.cubicbezier.ease;
                                scrollAnimation = new lib.animation(400,bezier,function(i1, i2) {
                                    var offset = s2 + _s * i2;
                                    setTransformStyle(that, offset.toFixed(2));
                                    fireEvent(that, 'scrolling', {
                                        afterFlick: true
                                    });
                                }
                                );
                                scrollAnimation.play().then(scrollEnd);
                            });
                        } else {
                            var offset = s2.toFixed(0);
                            setTransitionStyle(that, ((t1 + t2) / 1000).toFixed(2) + 's', 'ease-out');
                            setTransformStyle(that, offset);
                            setTransitionEndHandler(function(e) {
                                if (!that.enabled) {
                                    return;
                                }
                                debugLog('惯性回弹', 's=' + s1.toFixed(0), 't=400');
                                if (s2 !== s1) {
                                    var offset = s1.toFixed(0);
                                    setTransitionStyle(that, '0.4s', 'ease');
                                    setTransformStyle(that, offset);
                                    setTransitionEndHandler(scrollEnd, 400);
                                } else {
                                    scrollEnd();
                                }
                            }, ((t1 + t2) / 1000).toFixed(2) * 1000);
                        }
                    } else {
                        scrollEnd();
                    }
                } else {
                    debugLog('惯性计算没有超出边缘');
                    var timeFunction = motion0.generateCubicBezier();
                    if (options.useFrameAnimation) {
                        // frame;
                        var _s = s - s0;
                        var bezier = lib.cubicbezier(timeFunction[0][0], timeFunction[0][1], timeFunction[1][0], timeFunction[1][1]);
                        scrollAnimation = new lib.animation(t0.toFixed(0),bezier,function(i1, i2) {
                            var offset = (s0 + _s * i2).toFixed(2);
                            setTransformStyle(that, offset);
                            fireEvent(that, 'scrolling', {
                                afterFlick: true
                            });
                        }
                        );
                        scrollAnimation.play().then(scrollEnd);
                    } else {
                        // css
                        var offset = s.toFixed(0);
                        setTransitionStyle(that, (t0 / 1000).toFixed(2) + 's', 'cubic-bezier(' + timeFunction + ')');
                        setTransformStyle(that, offset);
                        setTransitionEndHandler(scrollEnd, (t0 / 1000).toFixed(2) * 1000);
                    }
                }
                isFlickScrolling = true;
                if (!options.useFrameAnimation) {
                    lib.animation.requestFrame(function() {
                        if (isScrolling && isFlickScrolling && that.enabled) {
                            fireEvent(that, 'scrolling', {
                                afterFlick: true
                            });
                            lib.animation.requestFrame(arguments.callee);
                        }
                    });
                }
            }
        }
        function scrollEnd() {
            if (!that.enabled) {
                return;
            }
            cancelScrollEnd = false;
            setTimeout(function() {
                if (!cancelScrollEnd && isScrolling) {
                    isScrolling = false;
                    isFlickScrolling = false;
                    if (options.useFrameAnimation) {
                        scrollAnimation && scrollAnimation.stop();
                        scrollAnimation = null;
                    } else {
                        setTransitionStyle(that, '', '');
                    }
                    fireEvent(that, 'scrollend');
                }
            }, 50);
        }
        var proto = {
            /**
         * 初始化
         * @instance
         * @memberOf lib.scroll~Scroll
         * @return {this} 当前对象
         */
            init: function() {
                this.enable();
                this.refresh();
                this.scrollTo(0);
                return this;
            },
            /**
         * 启用滚动
         * @instance
         * @memberOf lib.scroll~Scroll
         * @return {this} 当前对象
         */
            enable: function() {
                this.enabled = true;
                return this;
            },
            /**
         * 停止滚动
         * @instance
         * @memberOf lib.scroll~Scroll
         * @return {this} 当前对象
         */
            disable: function() {
                var el = this.element;
                this.enabled = false;
                if (this.options.useFrameAnimation) {
                    scrollAnimation && scrollAnimation.stop();
                } else {
                    lib.animation.requestFrame(function() {
                        el.style[stylePrefix + 'Transform'] = getComputedStyle(el)[stylePrefix + 'Transform'];
                    });
                }
                return this;
            },
            /**
         * 获得滚动元素的宽度（适用于x轴滚动）
         * @instance
         * @memberOf lib.scroll~Scroll
         * @return {Number}
         */
            getScrollWidth: function() {
                return getBoundingClientRect(this.element).width;
            },
            /**
         * 获得滚动元素的高度（适用于y轴滚动）
         * @instance
         * @memberOf lib.scroll~Scroll
         * @return {Number}
         */
            getScrollHeight: function() {
                return getBoundingClientRect(this.element).height;
            },
            /**
         * 获得滚动元素的滚动位置（适用于x轴滚动）
         * @instance
         * @memberOf lib.scroll~Scroll
         * @return {Number}
         */
            getScrollLeft: function() {
                return -getTransformOffset(this).x - this.options.xPaddingTop;
            },
            /**
         * 获得滚动元素的滚动位置（适用于y轴滚动）
         * @instance
         * @memberOf lib.scroll~Scroll
         * @return {Number}
         */
            getScrollTop: function() {
                return -getTransformOffset(this).y - this.options.yPaddingTop;
            },
            getMaxScrollLeft: function() {
                return -that.maxScrollOffset - this.options.xPaddingTop;
            },
            /**
         * 获得滚动元素的最大滚动位置（适用于x轴滚动）
         * @instance
         * @memberOf lib.scroll~Scroll
         * @return {Number}
         */
            getMaxScrollLeft: function() {
                return -that.maxScrollOffset - this.options.xPaddingTop;
            },
            /**
         * 获得滚动元素的最大滚动位置（适用于y轴滚动）
         * @instance
         * @memberOf lib.scroll~Scroll
         * @return {Number}
         */
            getMaxScrollTop: function() {
                return -that.maxScrollOffset - this.options.yPaddingTop;
            },
            /**
         * 获得回弹的距离
         * @instance
         * @memberOf lib.scroll~Scroll
         * @return {Number}
         */
            getBoundaryOffset: function() {
                return Math.abs(getBoundaryOffset(this, getTransformOffset(this)[this.axis]) || 0);
            },
            /**
         * 刷新滚动元素的高度
         * @instance
         * @memberOf lib.scroll~Scroll
         * @return {this} 当前对象
         */
            refresh: function() {
                var el = this.element;
                var isVertical = (this.axis === 'y');
                var type = isVertical ? 'height' : 'width';
                if (this.options[type] != null) {
                    // use options
                    el.style[type] = this.options[type] + 'px';
                } else if (!!this.options.useElementRect) {
                    el.style[type] = 'auto';
                    el.style[type] = getBoundingClientRect(el)[type] + 'px';
                } else if (el.childElementCount > 0) {
                    var range
                    var rect;
                    var firstEl = el.firstElementChild;
                    var lastEl = el.lastElementChild;
                    if (document.createRange && !this.options.ignoreOverflow) {
                        // use range
                        range = document.createRange();
                        range.selectNodeContents(el);
                        rect = getBoundingClientRect(range);
                    }
                    if (rect) {
                        el.style[type] = rect[type] + 'px';
                    } else {
                        // use child offsets
                        while (firstEl) {
                            if (getBoundingClientRect(firstEl)[type] === 0 && firstEl.nextElementSibling) {
                                firstEl = firstEl.nextElementSibling;
                            } else {
                                break;
                            }
                        }
                        while (lastEl && lastEl !== firstEl) {
                            if (getBoundingClientRect(lastEl)[type] === 0 && lastEl.previousElementSibling) {
                                lastEl = lastEl.previousElementSibling;
                            } else {
                                break;
                            }
                        }
                        el.style[type] = (getBoundingClientRect(lastEl)[isVertical ? 'bottom' : 'right'] - getBoundingClientRect(firstEl)[isVertical ? 'top' : 'left']) + 'px';
                    }
                }
                this.transformOffset = getTransformOffset(this);
                this.minScrollOffset = getMinScrollOffset(this);
                this.maxScrollOffset = getMaxScrollOffset(this);
                this.scrollTo(-this.transformOffset[this.axis] - this.options[this.axis + 'PaddingTop']);
                fireEvent(this, 'contentrefresh');
                return this;
            },
            /**
         * 获得某个元素在滚动元素内的偏移距离
         * @param {HTMLElement} childEl 滚动元素中的子元素
         * @instance
         * @memberOf lib.scroll~Scroll
         * @return {Object}
         */
            offset: function(childEl) {
                var elRect = getBoundingClientRect(this.element);
                var childRect = getBoundingClientRect(childEl);
                if (this.axis === 'y') {
                    var offsetRect = {
                        top: childRect.top - elRect.top - this.options.yPaddingTop,
                        left: childRect.left - elRect.left,
                        right: elRect.right - childRect.right,
                        width: childRect.width,
                        height: childRect.height
                    };
                    offsetRect.bottom = offsetRect.top + offsetRect.height;
                } else {
                    var offsetRect = {
                        top: childRect.top - elRect.top,
                        bottom: elRect.bottom - childRect.bottom,
                        left: childRect.left - elRect.left - this.options.xPaddingTop,
                        width: childRect.width,
                        height: childRect.height
                    };
                    offsetRect.right = offsetRect.left + offsetRect.width;
                }
                return offsetRect;
            },
            /**
         * 获得某个元素在滚动元素内的盒模型
         * @param {HTMLElement} childEl 滚动元素中的子元素
         * @instance
         * @memberOf lib.scroll~Scroll
         * @return {Object}
         */
            getRect: function(childEl) {
                var viewRect = getBoundingClientRect(this.viewport);
                var childRect = getBoundingClientRect(childEl);
                if (this.axis === 'y') {
                    var offsetRect = {
                        top: childRect.top - viewRect.top,
                        left: childRect.left - viewRect.left,
                        right: viewRect.right - childRect.right,
                        width: childRect.width,
                        height: childRect.height
                    };
                    offsetRect.bottom = offsetRect.top + offsetRect.height;
                } else {
                    var offsetRect = {
                        top: childRect.top - viewRect.top,
                        bottom: viewRect.bottom - childRect.bottom,
                        left: childRect.left - viewRect.left,
                        width: childRect.width,
                        height: childRect.height
                    };
                    offsetRect.right = offsetRect.left + offsetRect.width;
                }
                return offsetRect;
            },
            /**
         * 判断某个元素是否在可见范围内
         * @param {HTMLElement} childEl 滚动元素中的子元素
         * @instance
         * @memberOf lib.scroll~Scroll
         * @return {Boolean}
         */
            isInView: function(childEl) {
                var viewRect = this.getRect(this.viewport);
                var childRect = this.getRect(childEl);
                if (this.axis === 'y') {
                    return viewRect.top < childRect.bottom && viewRect.bottom > childRect.top;
                } else {
                    return viewRect.left < childRect.right && viewRect.right > childRect.left;
                }
            },
            /**
         * 滚动到某个位置
         * @param {Number} offset 位置
         * @param {Boolean} [isSmooth=false] 是否平滑，默认为false
         * @instance
         * @memberOf lib.scroll~Scroll
         * @return {this} 当前对象
         */
            scrollTo: function(offset, isSmooth) {
                var that = this;
                var element = this.element;
                offset = -offset - this.options[this.axis + 'PaddingTop'];
                offset = touchBoundary(this, offset);
                isScrolling = true;
                if (isSmooth === true) {
                    if (this.options.useFrameAnimation) {
                        var s0 = getTransformOffset(that)[this.axis];
                        var _s = offset - s0;
                        scrollAnimation = new lib.animation(400,lib.cubicbezier.ease,function(i1, i2) {
                            var offset = (s0 + _s * i2).toFixed(2);
                            setTransformStyle(that, offset);
                            fireEvent(that, 'scrolling');
                        }
                        );
                        scrollAnimation.play().then(scrollEnd);
                    } else {
                        setTransitionStyle(that, '0.4s', 'ease');
                        setTransformStyle(that, offset);
                        setTransitionEndHandler(scrollEnd, 400);
                        lib.animation.requestFrame(function() {
                            if (isScrolling && that.enabled) {
                                fireEvent(that, 'scrolling');
                                lib.animation.requestFrame(arguments.callee);
                            }
                        });
                    }
                } else {
                    if (!this.options.useFrameAnimation) {
                        setTransitionStyle(that, '', '');
                    }
                    setTransformStyle(that, offset);
                    scrollEnd();
                }
                return this;
            },
            /**
         * 滚动到某个元素
         * @param {HTMLElement} childEl 滚动元素中的子元素
         * @param {Boolean} [isSmooth=false] 是否平滑，默认为false
         * @instance
         * @memberOf lib.scroll~Scroll
         * @return {this} 当前对象
         */
            scrollToElement: function(childEl, isSmooth) {
                var offset = this.offset(childEl);
                offset = offset[this.axis === 'y' ? 'top' : 'left'];
                return this.scrollTo(offset, isSmooth);
            },
            /**
         * 获得可视区域的宽度
         * @instance
         * @memberOf lib.scroll~Scroll
         * @return {Number}
         */
            getViewWidth: function() {
                return getBoundingClientRect(this.viewport).width;
            },
            /**
         * 获得可视区域的高度
         * @instance
         * @memberOf lib.scroll~Scroll
         * @return {Number}
         */
            getViewHeight: function() {
                return getBoundingClientRect(this.viewport).height;
            },
            /**
         * 添加下拉操作的句柄
         * @param {Function} handler 句柄
         * @instance
         * @memberOf lib.scroll~Scroll
         * @return {this} 当前对象
         */
            addPulldownHandler: function(handler) {
                var that = this;
                this.element.addEventListener('pulldownend', function(e) {
                    that.disable();
                    handler.call(that, e, function() {
                        that.scrollTo(0, true);
                        that.refresh();
                        that.enable();
                    });
                }, false);
                return this;
            },
            /**
         * 添加上拉操作的句柄
         * @param {Function} handler 句柄
         * @instance
         * @memberOf lib.scroll~Scroll
         * @return {this} 当前对象
         */
            addPullupHandler: function(handler) {
                var that = this;
                this.element.addEventListener('pullupend', function(e) {
                    that.disable();
                    handler.call(that, e, function() {
                        that.scrollTo(that.getScrollHeight(), true);
                        that.refresh();
                        that.enable();
                    });
                }, false);
                return this;
            },
            /**
         * 添加滚动开始时的句柄
         * @param {Function} handler 句柄
         * @instance
         * @memberOf lib.scroll~Scroll
         * @return {this} 当前对象
         */
            addScrollstartHandler: function(handler) {
                var that = this;
                this.element.addEventListener('scrollstart', function(e) {
                    handler.call(that, e);
                }, false);
                return this;
            },
            /**
         * 添加滚动时的句柄
         * @param {Function} handler 句柄
         * @instance
         * @memberOf lib.scroll~Scroll
         * @return {this} 当前对象
         */
            addScrollingHandler: function(handler) {
                var that = this;
                this.element.addEventListener('scrolling', function(e) {
                    handler.call(that, e);
                }, false);
                return this;
            },
            /**
         * 添加滚动结束时的句柄
         * @param {Function} handler 句柄
         * @instance
         * @memberOf lib.scroll~Scroll
         * @return {this} 当前对象
         */
            addScrollendHandler: function(handler) {
                var that = this;
                this.element.addEventListener('scrollend', function(e) {
                    handler.call(that, e);
                }, false);
                return this;
            },
            /**
         * 添加刷新时的句柄
         * @param {Function} handler 句柄
         * @instance
         * @memberOf lib.scroll~Scroll
         * @return {this} 当前对象
         */
            addContentrenfreshHandler: function(handler) {
                var that = this;
                this.element.addEventListener('contentrefresh', function(e) {
                    handler.call(that, e);
                }, false);
                return this;
            },
            /**
         * 在滚动元素上添加事件
         * @param {String} name 事件名
         * @param {Function} handler 事件句柄
         * @param {Boolean} [useCapture] 是否捕获
         * @instance
         * @memberOf lib.scroll~Scroll
         * @return {this} 当前对象
         */
            addEventListener: function(name, handler, useCapture) {
                var that = this;
                this.element.addEventListener(name, function(e) {
                    handler.call(that, e);
                }, !!useCapture);
                return this;
            },
            /**
         * 在滚动元素上移除事件
         * @param {String} name 事件名
         * @param {Function} handler 事件句柄
         * @instance
         * @memberOf lib.scroll~Scroll
         * @return {this} 当前对象
         */
            removeEventListener: function(name, handler) {
                var that = this;
                this.element.removeEventListener(name, function(e) {
                    handler.call(that, e);
                });
                return this;
            },
            /**
         * 启用插件
         * @deprecated 从`2.6.0`版本开始已废弃
         */
            enablePlugin: function(name, options) {
                var plugin = plugins[name];
                if (plugin && !this.plugins[name]) {
                    this.plugins[name] = true;
                    options = options || {};
                    plugin.call(this, name, options);
                }
                return this;
            }
        }
        for (var k in proto) {
            this[k] = proto[k];
        }
        delete proto;
    }
    /**
 * @namespace lib
 */
    /**
 * 生成Scroll对象实例
 * @param  {HTMLElement} el  需要滚动的元素
 * @param  {Object} options 设置
 * @param  {HTMLElement} [options.scrollElement] 需要滚动的元素
 * @param  {HTMLElement} [options.scrollWrap] 需要滚动元素的父元素
 * @param  {String} [options.direction='y'] 滚动的方向，默认是“y”，即垂直滚动。如需水平滚动，就设置为“x”
 * @param  {HTMLElement} [options.downgrade=false] 是否降级，默认为false，如需降级，请设置为true，并引入downgrade.js
 * @param  {Boolean} [options.noBounce=false] 边缘是否回弹效果，默认为false
 * @param  {String} [options.inertia='normal'] 惯性的类型，可取值为normal，slow，veryslow
 * @param  {Boolean} [options.isPrevent=true] 阻止默认滚动，默认为true
 * @param  {Boolean} [options.isFixScrollendClick=true] 点停滚动时，触发点击事件的问题，默认为true
 * @param  {Boolean} [options.useFrameAnimation=false] 用帧动画实现滚动，默认为false
 * @return {lib.scroll~Scroll}         Scroll类实例
 */
    lib.scroll = function(el, options) {
        if (arguments.length === 1 && !(arguments[0]instanceof HTMLElement)) {
            options = arguments[0];
            if (options.scrollElement) {
                el = options.scrollElement;
            } else if (options.scrollWrap) {
                el = options.scrollWrap.firstElementChild;
            } else {
                throw new Error('no scroll element');
            }
        }
        if (!el.parentNode) {
            throw new Error('wrong dom tree');
        }
        if (options && options.direction && ['x', 'y'].indexOf(options.direction) < 0) {
            throw new Error('wrong direction');
        }
        var scroll;
        if (options.downgrade === true && lib.scroll.downgrade) {
            scroll = lib.scroll.downgrade(el, options);
        } else {
            if (el.scrollId) {
                scroll = scrollObjs[el.scrollId];
            } else {
                scroll = new Scroll(el,options);
            }
        }
        return scroll;
    }
    /**
 * 增加插件
 * @deprecated 从`2.6.0`版本开始已废弃
 */
    lib.scroll.plugin = function(name, constructor) {
        if (constructor) {
            name = name.split(',');
            name.forEach(function(n) {
                plugins[n] = constructor;
            });
        } else {
            return plugins[name];
        }
    }
})(window, window['lib'] || (window['lib'] = {}));
;(function(win, lib, undef) {
    var doc = win.document;
    var scrollObjs = {};
    var plugins = {};
    function debugLog() {
        if (lib.scroll.outputDebugLog) {
            console.debug.apply(console, arguments);
        }
    }
    function getBoundingClientRect(el) {
        var rect = el.getBoundingClientRect();
        if (!rect) {
            rect = {};
            rect.width = el.offsetWidth;
            rect.height = el.offsetHeight;
            rect.left = el.offsetLeft;
            rect.top = el.offsetTop;
            var parent = el.offsetParent;
            while (parent) {
                rect.left += parent.offsetLeft;
                rect.top += parent.offsetTop;
                parent = parent.offsetParent;
            }
            rect.right = rect.left + rect.width;
            rect.bottom = rect.top + rect.height;
        }
        return rect;
    }
    function getMinScrollOffset(scrollObj) {
        return 0 - scrollObj.options[scrollObj.axis + 'PaddingTop'];
    }
    function getMaxScrollOffset(scrollObj) {
        var rect = getBoundingClientRect(scrollObj.element);
        var pRect = getBoundingClientRect(scrollObj.viewport);
        var min = getMinScrollOffset(scrollObj);
        if (scrollObj.axis === 'y') {
            var max = 0 - rect.height + pRect.height;
        } else {
            var max = 0 - rect.width + pRect.width;
        }
        return Math.min(max + scrollObj.options[scrollObj.axis + 'PaddingBottom'], min);
    }
    function getBoundaryOffset(scrollObj, offset) {
        if (offset > scrollObj.minScrollOffset) {
            return offset - scrollObj.minScrollOffset;
        } else if (offset < scrollObj.maxScrollOffset) {
            return offset - scrollObj.maxScrollOffset;
        }
    }
    function fireEvent(scrollObj, eventName, extra) {
        debugLog(scrollObj.element.scrollId, eventName, extra);
        var event = doc.createEvent('HTMLEvents');
        event.initEvent(eventName, false, true);
        event.scrollObj = scrollObj;
        if (extra) {
            for (var key in extra) {
                event[key] = extra[key];
            }
        }
        scrollObj.element.dispatchEvent(event);
        scrollObj.viewport.dispatchEvent(event);
    }
    function ScrollDowngrade(element, options) {
        var that = this;
        options = options || {};
        options.noBounce = !!options.noBounce;
        options.padding = options.padding || {};
        if (options.isPrevent == null) {
            options.isPrevent = true;
        } else {
            options.isPrevent = !!options.isPrevent;
        }
        if (options.isFixScrollendClick == null) {
            options.isFixScrollendClick = true;
        } else {
            options.isFixScrollendClick = !!options.isFixScrollendClick;
        }
        if (options.padding) {
            options.yPaddingTop = -options.padding.top || 0;
            options.yPaddingBottom = -options.padding.bottom || 0;
            options.xPaddingTop = -options.padding.left || 0;
            options.xPaddingBottom = -options.padding.right || 0;
        } else {
            options.yPaddingTop = 0;
            options.yPaddingBottom = 0;
            options.xPaddingTop = 0;
            options.xPaddingBottom = 0;
        }
        options.direction = options.direction || 'y';
        options.inertia = options.inertia || 'normal';
        this.options = options;
        that.axis = options.direction;
        this.element = element;
        this.viewport = element.parentNode;
        this.plugins = {};
        this.element.scrollId = setTimeout(function() {
            scrollObjs[that.element.scrollId + ''] = that;
        }, 1);
        this.viewport.style.overflow = 'hidden';
        this.viewport.style['overflow' + this.axis.toUpperCase()] = 'scroll';
        this.viewport.style.webkitOverflowScrolling = 'touch';
        this.viewport.style.msOverflowScrolling = 'touch';
        this.viewport.style.overflowScrolling = 'touch';
        var isPaning = false;
        var isScrollStart = false;
        var isScrolling = false;
        this.viewport.addEventListener('scroll', function(e) {
            if (!isScrollStart)
                return;
            fireEvent(that, 'scrolling');
            var scrollOffset = that.axis === 'y' ? that.getScrollTop() : that.getScrollLeft();
            setTimeout(function() {
                var endScrollOffset = that.axis === 'y' ? that.getScrollTop() : that.getScrollLeft();
                if (scrollOffset === endScrollOffset && !isPaning) {
                    fireEvent(that, 'scrollend');
                }
            }, 50);
        });
        var pullDirection = false;
        var pullDisplacementStart = 0;
        this.viewport.addEventListener('panstart', function(e) {
            isPaning = true;
            pullDirection = false;
            pullDisplacementStart = 0;
            fireEvent(that, 'scrollstart');
        });
        this.viewport.addEventListener('pan', function(e) {
            var offset = that.axis === 'y' ? that.getScrollTop() : that.getScrollLeft();
            var maxOffset = that.axis === 'y' ? that.getScrollHeight() - that.getViewHeight() : that.getScrollWidth() - that.getViewWidth();
            if (offset === 0 || offset === maxOffset) {
                if (!pullDisplacementStart) {
                    pullDisplacementStart = e['displacement' + that.axis.toUpperCase()];
                } else {
                    if (e.displacementY > 0) {
                        pullDirection = that.axis === 'y' ? 'down' : 'right';
                    } else if (e.displacementY < 0) {
                        pullDirection = that.axis === 'y' ? 'up' : 'left';
                    }
                    var boundaryOffset = e.displacementY - pullDisplacementStart;
                    if ((pullDirection === 'down' || pullDirection === 'right') && boundaryOffset > 0 && offset === 0) {
                        fireEvent(that, 'pull' + pullDirection, {
                            boundaryOffset: Math.abs(boundaryOffset)
                        });
                    } else if ((pullDirection === 'up' || pullDirection === 'left') && boundaryOffset < 0 && offset === maxOffset) {
                        fireEvent(that, 'pull' + pullDirection, {
                            boundaryOffset: Math.abs(boundaryOffset)
                        });
                    } else {
                        pullDirection = false;
                        pullDisplacementStart = 0;
                    }
                }
            } else {
                pullDirection = false;
                pullDisplacementStart = 0;
            }
        });
        this.viewport.addEventListener('panend', function(e) {
            isPaning = false;
            if (pullDirection) {
                fireEvent(that, 'pull' + pullDirection + 'end');
                pullDirection = false;
                pullDisplacementStart = 0;
            }
            var scrollOffset = that.axis === 'y' ? that.getScrollTop() : that.getScrollLeft();
            setTimeout(function() {
                var endScrollOffset = that.axis === 'y' ? that.getScrollTop() : that.getScrollLeft();
                if (scrollOffset === endScrollOffset && !isPaning) {
                    fireEvent(that, 'scrollend');
                }
            }, 50);
        });
        this.viewport.addEventListener('touchmove', function(e) {
            if (pullDirection) {
                e.preventDefault();
            }
        }, false);
        this.viewport.addEventListener('scrollstart', function(e) {
            isScrollStart = true;
            isScrolling = true;
        }, false);
        this.viewport.addEventListener('scrolling', function(e) {
            isScrolling = true;
        }, false);
        this.viewport.addEventListener('scrollend', function(e) {
            isScrollStart = false;
            isScrolling = false;
        }, false);
        this.viewport.addEventListener('click', function(e) {
            var niceTapEvent = document.createEvent('HTMLEvents');
            niceTapEvent.initEvent('niceclick', true, true);
            e.target.dispatchEvent(niceTapEvent);
        }, false);
        var proto = {
            init: function() {
                this.enable();
                this.refresh();
                this.scrollTo(0);
                return this;
            },
            enable: function() {
                this.enabled = true;
                return this;
            },
            disable: function() {
                this.enabled = false;
                return this;
            },
            getScrollWidth: function() {
                return getBoundingClientRect(this.element).width;
            },
            getScrollHeight: function() {
                return getBoundingClientRect(this.element).height;
            },
            getScrollLeft: function() {
                return this.viewport.scrollLeft - this.options.xPaddingTop;
            },
            getScrollTop: function() {
                return this.viewport.scrollTop - this.options.yPaddingTop;
            },
            getMaxScrollLeft: function() {
                return -getMaxScrollOffset(this) - this.options.xPaddingTop;
            },
            getMaxScrollTop: function() {
                return -getMaxScrollOffset(this) - this.options.yPaddingTop;
            },
            getBoundaryOffset: function() {
                return Math.abs(getBoundaryOffset(this, this['getScroll' + (this.axis === 'y' ? 'Top' : 'Left')]) || 0);
            },
            refresh: function() {
                if (this.axis === 'y') {
                    this.element.style.paddingTop = -this.options.yPaddingTop + 'px';
                    this.element.style.paddingBottom = -this.options.yPaddingBottom + 'px';
                } else {
                    this.element.style.paddingLeft = -this.options.xPaddingTop + 'px';
                    this.element.style.paddingRight = -this.options.xPaddingBottom + 'px';
                }
                fireEvent(this, 'contentrefresh');
                return this;
            },
            offset: function(childEl) {
                var elRect = getBoundingClientRect(this.element);
                var childRect = getBoundingClientRect(childEl);
                if (this.axis === 'y') {
                    var offsetRect = {
                        top: childRect.top - elRect.top - this.options.yPaddingTop,
                        left: childRect.left - elRect.left,
                        right: elRect.right - childRect.right,
                        width: childRect.width,
                        height: childRect.height
                    };
                    offsetRect.bottom = offsetRect.top + offsetRect.height;
                } else {
                    var offsetRect = {
                        top: childRect.top - elRect.top,
                        bottom: elRect.bottom - childRect.bottom,
                        left: childRect.left - elRect.left - this.options.xPaddingTop,
                        width: childRect.width,
                        height: childRect.height
                    };
                    offsetRect.right = offsetRect.left + offsetRect.width;
                }
                return offsetRect;
            },
            getRect: function(childEl) {
                var viewRect = getBoundingClientRect(this.viewport);
                var childRect = getBoundingClientRect(childEl);
                if (this.axis === 'y') {
                    var offsetRect = {
                        top: childRect.top - viewRect.top,
                        left: childRect.left - viewRect.left,
                        right: viewRect.right - childRect.right,
                        width: childRect.width,
                        height: childRect.height
                    };
                    offsetRect.bottom = offsetRect.top + offsetRect.height;
                } else {
                    var offsetRect = {
                        top: childRect.top - viewRect.top,
                        bottom: viewRect.bottom - childRect.bottom,
                        left: childRect.left - viewRect.left,
                        width: childRect.width,
                        height: childRect.height
                    };
                    offsetRect.right = offsetRect.left + offsetRect.width;
                }
                return offsetRect;
            },
            isInView: function(childEl) {
                var viewRect = this.getRect(this.viewport);
                var childRect = this.getRect(childEl);
                if (this.axis === 'y') {
                    return viewRect.top < childRect.bottom && viewRect.bottom > childRect.top;
                } else {
                    return viewRect.left < childRect.right && viewRect.right > childRect.left;
                }
            },
            scrollTo: function(offset) {
                var that = this;
                var element = this.element;
                var type = this.axis === 'y' ? 'Top' : 'Left';
                isScrolling = true;
                this.viewport['scroll' + type] = offset;
                fireEvent(this, 'scrollend');
                return this;
            },
            scrollToElement: function(childEl, isSmooth) {
                var offset = this.offset(childEl);
                offset = offset[this.axis === 'y' ? 'top' : 'left'];
                return this.scrollTo(offset, isSmooth);
            },
            getViewWidth: function() {
                return getBoundingClientRect(this.viewport).width;
            },
            getViewHeight: function() {
                return getBoundingClientRect(this.viewport).height;
            },
            addPulldownHandler: function(handler) {
                var that = this;
                this.element.addEventListener('pulldownend', function(e) {
                    that.disable();
                    handler.call(that, function() {
                        that.enable();
                    });
                }, false);
                return this;
            },
            addPullupHandler: function(handler) {
                var that = this;
                this.element.addEventListener('pullupend', function(e) {
                    that.disable();
                    handler.call(that, function() {
                        that.enable();
                    });
                }, false);
                return this;
            },
            addScrollstartHandler: function(handler) {
                var that = this;
                this.element.addEventListener('scrollstart', function(e) {
                    handler.call(that, e);
                }, false);
                return this;
            },
            addScrollingHandler: function(handler) {
                var that = this;
                this.element.addEventListener('scrolling', function(e) {
                    handler.call(that, e);
                }, false);
                return this;
            },
            addScrollendHandler: function(handler) {
                var that = this;
                this.element.addEventListener('scrollend', function(e) {
                    handler.call(that, e);
                }, false);
                return this;
            },
            addContentrenfreshHandler: function(handler) {
                var that = this;
                this.element.addEventListener('contentrefresh', function(e) {
                    handler.call(that, e);
                }, false);
            },
            addEventListener: function(name, handler, useCapture) {
                var that = this;
                this.element.addEventListener(name, function(e) {
                    handler.call(that, e);
                }, !!useCapture);
            },
            removeEventListener: function(name, handler) {
                var that = this;
                this.element.removeEventListener(name, function(e) {
                    handler.call(that, e);
                });
            }
        }
        for (var k in proto) {
            this[k] = proto[k];
        }
        delete proto;
    }
    if (!lib.scroll) {
        lib.scroll = function(el, options) {
            if (arguments.length === 1 && !(arguments[0]instanceof HTMLElement)) {
                options = arguments[0];
                if (options.scrollElement) {
                    el = options.scrollElement;
                } else if (options.scrollWrap) {
                    el = options.scrollWrap.firstElementChild;
                } else {
                    throw new Error('no scroll element');
                }
            }
            if (!el.parentNode) {
                throw new Error('wrong dom tree');
            }
            if (options && options.direction && ['x', 'y'].indexOf(options.direction) < 0) {
                throw new Error('wrong direction');
            }
            var scroll;
            if (el.scrollId) {
                scroll = scrollObjs[el.scrollId];
            } else {
                scroll = new ScrollDowngrade(el,options);
            }
            return scroll;
        }
    } else {
        lib.scroll.downgrade = function(el, options) {
            var scroll;
            if (el.scrollId) {
                scroll = scrollObjs[el.scrollId];
            } else {
                scroll = new ScrollDowngrade(el,options);
            }
            return scroll;
        }
    }
})(window, window['lib'] || (window['lib'] = {}));
!function() {
    var a = '[data-ctrl-name=loading]{width:100%;height:100%;display:-ms-flexbox;-ms-flex-align:center;-ms-flex-pack:center;display:-webkit-box;-webkit-box-align:center;-webkit-box-pack:center;display:-moz-box;-moz-box-align:center;-moz-box-pack:center}[data-ctrl-name=loading] [rol=draw]{position:relative;display:none}[data-ctrl-name=loading] [rol=draw] .arrow{display:none;position:absolute;left:0;top:0;width:100%;height:100%;background-position:center center;background-repeat:no-repeat;background-size:contain}[data-ctrl-name=loading] [rol=draw] .arrow.down{display:block;background-image:url()}[data-ctrl-name=loading] [rol=draw] .arrow.up{display:block;background-image:url()}[data-dpr="1"] [data-ctrl-name=loading] [rol=draw],[data-dpr="1"] [data-ctrl-name=loading] [rol=spin],[data-dpr="1"] [data-ctrl-name=loading] canvas{width:30px;height:30px}[data-dpr="2"] [data-ctrl-name=loading] [rol=draw],[data-dpr="2"] [data-ctrl-name=loading] [rol=spin],[data-dpr="2"] [data-ctrl-name=loading] canvas{width:60px;height:60px}[data-dpr="3"] [data-ctrl-name=loading] [rol=draw],[data-dpr="3"] [data-ctrl-name=loading] [rol=spin],[data-dpr="3"] [data-ctrl-name=loading] canvas{width:90px;height:90px}[data-ctrl-name=loading] [rol=spin]{position:relative;display:none}[data-ctrl-name=loading] [rol=spin] .circle{position:absolute;width:100%;height:100%;border-radius:50%;border:1px solid #999;box-sizing:border-box;-webkit-animation:spinner .6s linear infinite;-ms-animation:spinner .6s linear infinite;animation:spinner .6s linear infinite}[data-ctrl-name=loading] [rol=spin] .circle span{background-color:#fff;display:block;position:absolute;width:8px;height:4px;left:-1px;margin-top:-2px;top:50%;content:\'\'}@-webkit-keyframes spinner{0%{-webkit-transform:rotate(90deg)}100%{-webkit-transform:rotate(-270deg)}}@keyframes spinner{0%{transform:rotate(90deg)}100%{transform:rotate(-270deg)}}[data-dpr="1"] [data-ctrl-name=loading] [rol=spin] .circle{width:30px;height:30px;border-width:1px}[data-dpr="2"] [data-ctrl-name=loading] [rol=spin] .circle{width:60px;height:60px;border-width:2px}[data-dpr="3"] [data-ctrl-name=loading] [rol=spin] .circle{width:90px;height:90px;border-width:3px}[data-dpr="1"] [data-ctrl-name=loading] [rol=spin] .circle span{width:8px;height:4px;left:-1px;margin-top:-2px}[data-dpr="2"] [data-ctrl-name=loading] [rol=spin] .circle span{width:16px;height:8px;left:-2px;margin-top:-4px}[data-dpr="3"] [data-ctrl-name=loading] [rol=spin] .circle span{width:24px;height:12px;left:-3px;margin-top:-6px}[data-ctrl-name=loading] .text{display:block;color:#999;margin-left:.3rem}[data-dpr="1"] [data-ctrl-name=loading] .text{height:30px;line-height:30px;font-size:12px}[data-dpr="2"] [data-ctrl-name=loading] .text{height:60px;line-height:60px;font-size:24px}[data-dpr="3"] [data-ctrl-name=loading] .text{height:90px;line-height:90px;font-size:36px}'
      , b = document.createElement("style");
    if (document.getElementsByTagName("head")[0].appendChild(b),
    b.styleSheet)
        b.styleSheet.disabled || (b.styleSheet.cssText = a);
    else
        try {
            b.innerHTML = a
        } catch (c) {
            b.innerText = a
        }
}();
;(function(win, lib, ctrl) {
    var doc = win.document;
    var ua = win.navigator.userAgent;
    var Firefox = !!ua.match(/Firefox/i);
    var IEMobile = !!ua.match(/IEMobile/i);
    var cssPrefix = Firefox ? '-moz-' : IEMobile ? '-ms-' : '-webkit-';
    var stylePrefix = Firefox ? 'Moz' : IEMobile ? 'ms' : 'webkit';
    function setHTMLElement(parent, child) {
        if (typeof child === 'string') {
            parent.innerHTML = child;
        } else if (child instanceof HTMLElement) {
            parent.innerHTML = '';
            parent.appendChild(child);
        } else if (child instanceof Array || child instanceof NodeList) {
            var fragment = doc.createDocumentFragment();
            Array.prototype.slice.call(child).forEach(function(node) {
                fragment.appendChild(node);
            });
            parent.appendChild(fragment);
        }
    }
    function getTransformOffset(element) {
        var offset = {
            x: 0,
            y: 0
        };
        var transform = getComputedStyle(element)[stylePrefix + 'Transform'];
        var matched;
        if (transform !== 'none') {
            if ((matched = transform.match(/^matrix3d\((?:[-\d.]+,\s*){12}([-\d.]+),\s*([-\d.]+)(?:,\s*[-\d.]+){2}\)/) || transform.match(/^matrix\((?:[-\d.]+,\s*){4}([-\d.]+),\s*([-\d.]+)\)$/)) ) {
                offset.x = parseFloat(matched[1]) || 0;
                offset.y = parseFloat(matched[2]) || 0;
            }
        }
        return offset;
    }
    var CSSMatrix = IEMobile ? 'MSCSSMatrix' : 'WebKitCSSMatrix';
    var has3d = !!Firefox || CSSMatrix in win && 'm11'in new win[CSSMatrix]();
    function getTranslate(x, y) {
        x = parseFloat(x);
        y = parseFloat(y);
        if (x != 0) {
            x += 'px';
        }
        if (y != 0) {
            y += 'px';
        }
        if (has3d) {
            return 'translate3d(' + x + ', ' + y + ', 0)';
        } else {
            return 'translate(' + x + ', ' + y + ')';
        }
    }
    function setTransitionStyle(element, duration, timingFunction) {
        if (arguments.length === 1) {
            element.style[stylePrefix + 'Transition'] = '';
        } else {
            element.style[stylePrefix + 'Transition'] = cssPrefix + 'transform ' + duration + ' ' + timingFunction + ' 0s';
        }
    }
    function setTransformStyle(element, x, y) {
        element.style[stylePrefix + 'Transform'] = getTranslate(x, y);
    }
    var incId = 0;
    /**
 * @class ctrl.scrollview~ScrollView
 * @param {HTMLElement} root 滚动视图的根元素
 * @param {Obejct} [options] 设置，同`lib.scroll`的设置
 * @return {ctrl.scrollview~ScrollView} ScrollView的实例
 */
    function ScrollView(root, options) {
        function fireEvent(name, extra) {
            var ev = doc.createEvent('HTMLEvents');
            ev.initEvent(name, false, false);
            if (extra) {
                for (var key in extra) {
                    ev[key] = extra[key];
                }
            }
            scroll.element.dispatchEvent(ev);
        }
        var that = this;
        var id = Date.now() + '-' + (++incId);
        if (arguments.length === 1 && !(arguments[0]instanceof HTMLElement)) {
            options = arguments[0];
            root = null;
        }
        options = options || {};
        if (!root) {
            root = doc.createElement('div');
        }
        var scrollWrap = root.firstElementChild || doc.createElement('div');
        var scrollElement = scrollWrap.firstElementChild || doc.createElement('div');
        if (!scrollWrap.parentNode) {
            root.appendChild(scrollWrap);
        }
        if (!scrollElement.parentNode) {
            scrollWrap.appendChild(scrollElement);
        }
        root.setAttribute('data-ctrl-name', 'scrollview');
        root.setAttribute('data-ctrl-id', id);
        root.setAttribute('data-direction', options.direction !== 'x' ? 'vertical' : 'horizontal');
        if (scrollWrap.className.indexOf('scroll-wrap') < 0) {
            scrollWrap.className = scrollWrap.className.split(' ').concat('scroll-wrap').join(' ').replace(/^\s+/, '');
        }
        if (scrollElement.className.indexOf('scroll-content') < 0) {
            scrollElement.className = scrollElement.className.split(' ').concat('scroll-content').join(' ').replace(/^\s+/, '');
        }
        options.scrollElement = scrollElement;
        options.scrollWrap = scrollWrap;
        var scroll = new lib.scroll(options);
        /**
     * @member scrollWrap
     * @instance
     * @memberOf ctrl.scrollview~ScrollView
     * @description 滚动视图中滚动元素的父元素
     * @type {HTMLElement}
     */
        this.scrollWrap = scrollWrap;
        /**
     * @member scrollElement
     * @instance
     * @memberOf ctrl.scrollview~ScrollView
     * @description 滚动视图中滚动元素
     * @type {HTMLElement}
     */
        this.scrollElement = scrollElement;
        /**
     * @member scroll
     * @instance
     * @memberOf ctrl.scrollview~ScrollView
     * @description 滚动对象实例
     * @type {lib.scroll~Scroll}
     */
        this.scroll = scroll;
        /**
     * @member root
     * @instance
     * @memberOf ctrl.scrollview~ScrollView
     * @description 滚动视图的根元素
     * @type {HTMLElement}
     */
        this.root = this.element = root;
        for (var name in scroll) {
            void function(name) {
                if (typeof scroll[name] === 'function') {
                    that[name] = function() {
                        return scroll[name].apply(scroll, arguments);
                    }
                } else if (!that[name]) {
                    Object.defineProperty(that, name, {
                        get: function() {
                            return scroll[name];
                        },
                        set: function(v) {
                            scroll[name] = v;
                        }
                    })
                }
            }(name);
        }
        /**
     * @member forceRepaint
     * @instance
     * @memberOf ctrl.scrollview~ScrollView
     * @description 强制重绘的相关配置
     * @type {ctrl.scrollview~ForceRepaint}
     */
        Object.defineProperty(this, 'forceRepaint', {
            value: new ForceRepaint(this)
        });
        /**
     * @member fixed
     * @instance
     * @memberOf ctrl.scrollview~ScrollView
     * @description 元素fixed的相关配置
     * @type {ctrl.scrollview~Fixed}
     */
        Object.defineProperty(this, 'fixed', {
            value: new Fixed(this)
        });
        /**
     * @member lazyload
     * @instance
     * @memberOf ctrl.scrollview~ScrollView
     * @description 图片懒加载的相关配置
     * @type {ctrl.scrollview~Lazyload}
     */
        Object.defineProperty(this, 'lazyload', {
            value: new Lazyload(this)
        });
        /**
     * @member sticky
     * @instance
     * @memberOf ctrl.scrollview~ScrollView
     * @description 元素吸顶的相关配置
     * @type {ctrl.scrollview~Sticky}
     */
        Object.defineProperty(this, 'sticky', {
            value: new Sticky(this)
        });
        /**
     * @member pullRefresh
     * @instance
     * @memberOf ctrl.scrollview~ScrollView
     * @description 下拉刷新的相关配置
     * @type {ctrl.scrollview~Refresh}
     */
        Object.defineProperty(this, 'pullRefresh', {
            value: new Refresh(this)
        });
        // refersh init
        (function() {
            if (scroll.axis !== 'y')
                return;
            var height = win.dpr ? win.dpr * 60 : 60;
            var processingText = '下拉即可刷新...';
            var refreshText = '正在刷新...';
            var refreshLoading = new ctrl.loading();
            refreshLoading.arrowDirection = 'down';
            refreshLoading.mode = 'draw';
            refreshLoading.bgcolor = '#FFF';
            refreshLoading.text = processingText;
            var element = refreshLoading.element;
            that.pullRefresh.element = element;
            that.pullRefresh.height = height;
            that.pullRefresh.processingHandler = function(offset) {
                if (refreshLoading.mode !== 'draw') {
                    refreshLoading.mode = 'draw';
                }
                if (refreshLoading.text !== processingText) {
                    refreshLoading.text = processingText;
                }
                refreshLoading.per = Math.round(offset / height * 100);
            }
            that.pullRefresh.refreshHandler = function(done) {
                var isDone = false;
                refreshLoading.text = refreshText;
                refreshLoading.mode = 'spin';
                that.pullRefresh.handler && that.pullRefresh.handler(function() {
                    if (isDone)
                        return;
                    isDone = true;
                    done();
                });
            }
        })();
        /**
     * @member pullUpdate
     * @instance
     * @memberOf ctrl.scrollview~ScrollView
     * @description 上拉更新的相关配置
     * @type {ctrl.scrollview~Update}
     */
        Object.defineProperty(this, 'pullUpdate', {
            value: new Update(this)
        });
        // update init
        (function() {
            if (scroll.axis !== 'y')
                return;
            var height = win.dpr ? win.dpr * 60 : 60;
            var processingText = '上拉加载更多...';
            var updateText = '正在加载...';
            var updateLoading = new ctrl.loading();
            updateLoading.arrowDirection = 'up';
            updateLoading.mode = 'draw';
            updateLoading.bgcolor = '#FFF';
            updateLoading.text = processingText;
            var element = updateLoading.element;
            that.pullUpdate.element = element;
            that.pullUpdate.height = height;
            that.pullUpdate.processingHandler = function(offset) {
                if (updateLoading.mode !== 'draw') {
                    updateLoading.mode = 'draw';
                }
                if (updateLoading.text !== processingText) {
                    updateLoading.text = processingText;
                }
                updateLoading.per = Math.round(offset / height * 100);
            }
            that.pullUpdate.updateHandler = function(done) {
                var isDone = false;
                updateLoading.text = updateText;
                updateLoading.mode = 'spin';
                that.pullUpdate.handler && that.pullUpdate.handler(function() {
                    if (isDone)
                        return;
                    isDone = true;
                    done();
                });
            }
        })();
        /**
     * @member content
     * @instance
     * @memberOf ctrl.scrollview~ScrollView
     * @description 滚动视图的内容
     * @type {HTMLElement|String}
     */
        Object.defineProperty(this, 'content', {
            get: function() {
                return Array.prototype.slice.call(scrollElement.children);
            },
            set: function(content) {
                setHTMLElement(scrollElement, content);
            }
        });
    }
    /**
 * 强制重绘的插件
 * @class ctrl.scrollview~ForceRepaint
 * @param {ctrl.scrollview~ScrollView} view 视图对象实例
 * @return {ctrl.scrollview~ForceRepaint} 实例
 */
    function ForceRepaint(view) {
        var scroll = view.scroll;
        var forceRepaintElement = doc.createElement('div');
        forceRepaintElement.className = 'force-repaint';
        forceRepaintElement.style.cssText = 'position: absolute; top: 0; left: 0; width: 0; height: 0; font-size: 0; opacity: 1;';
        view.root.appendChild(forceRepaintElement);
        var enable = false;
        /**
     * @member enable
     * @instance
     * @memberOf ctrl.scrollview~ForceRepaint
     * @description 启用强制重绘
     * @type {Boolean}
     */
        Object.defineProperty(this, 'enable', {
            get: function() {
                return enable;
            },
            set: function(v) {
                enable = v;
            }
        }, false);
        Object.defineProperty(this, 'element', {
            value: forceRepaintElement
        });
        scroll.addScrollingHandler(function() {
            if (!enable)
                return;
            forceRepaintElement.style.opacity = Math.abs(parseInt(forceRepaintElement.style.opacity) - 1) + '';
        });
    }
    /**
 * 元素固定的插件
 * @class ctrl.scrollview~Fixed
 * @param {ctrl.scrollview~ScrollView} view 视图对象实例
 * @return {ctrl.scrollview~Fixed} 实例
 */
    function Fixed(view) {
        var that = this;
        var scroll = view.scroll;
        var fragment = doc.createDocumentFragment();
        var topFixedElement;
        var bottomFixedElement;
        var leftFixedElement;
        var rightFixedElement;
        var enable = false;
        /**
     * @member enable
     * @instance
     * @memberOf ctrl.scrollview~Fixed
     * @description 启用元素固定
     * @type {Boolean}
     */
        Object.defineProperty(that, 'enable', {
            get: function() {
                return enable;
            },
            set: function(v) {
                enable = v;
                if (!!enable) {
                    if (topFixedElement) {
                        if (!topFixedElement.parentNode) {
                            view.root.insertBefore(topFixedElement, view.scrollWrap);
                        }
                        topFixedElement.style.display = 'block';
                    }
                    if (bottomFixedElement) {
                        if (!bottomFixedElement.parentNode) {
                            view.root.appendChild(bottomFixedElement);
                        }
                        bottomFixedElement.style.display = 'block';
                    }
                    if (leftFixedElement) {
                        if (!leftFixedElement.parentNode) {
                            view.root.insertBefore(leftFixedElement, view.scrollWrap);
                        }
                        leftFixedElement.style.display = 'block';
                    }
                    if (rightFixedElement) {
                        if (!rightFixedElement.parentNode) {
                            view.root.appendChild(rightFixedElement);
                        }
                        rightFixedElement.style.display = 'block';
                    }
                } else {
                    topFiexElement && (topFixedElement.style.display = 'none');
                    bottomFixedElement && (bottomFixedElement.style.display = 'none');
                    leftFixedElement && (leftFixedElement.style.display = 'none');
                    rightFixedElement && (rightFixedElement.style.display = 'none');
                }
            }
        });
        if (scroll.axis === 'y') {
            topFixedElement = doc.createElement('div');
            topFixedElement.className = 'top-fixed';
            topFixedElement.style.cssText = 'left: 0; top: 0; width: 100%;';
            /**
         * @member topElement
         * @instance
         * @memberOf ctrl.scrollview~Fixed
         * @description 固定在顶部的元素
         * @type {HTMLElement}
         */
            Object.defineProperty(that, 'topElement', {
                get: function() {
                    return topFixedElement;
                },
                set: function(v) {
                    setHTMLElement(topFixedElement, v);
                }
            });
            /**
         * @member topOffset
         * @instance
         * @memberOf ctrl.scrollview~Fixed
         * @description 离顶部的距离
         * @type {Number}
         */
            Object.defineProperty(that, 'topOffset', {
                set: function(v) {
                    topFixedElement.style.top = v + 'px';
                }
            });
            bottomFixedElement = this.bottomFixedElement = doc.createElement('div');
            bottomFixedElement.className = 'bottom-fxied';
            bottomFixedElement.style.cssText = 'left: 0; bottom: 0; width: 100%;';
            /**
         * @member bottomElement
         * @instance
         * @memberOf ctrl.scrollview~Fixed
         * @description 固定在底部的元素
         * @type {HTMLElement}
         */
            Object.defineProperty(that, 'bottomElement', {
                get: function() {
                    return bottomFixedElement;
                },
                set: function(v) {
                    setHTMLElement(bottomFixedElement, v);
                }
            });
            /**
         * @member bottomOffset
         * @instance
         * @memberOf ctrl.scrollview~Fixed
         * @description 离底部的距离
         * @type {Number}
         */
            Object.defineProperty(that, 'bottomOffset', {
                set: function(v) {
                    bottomFixedElement.style.top = v + 'px';
                }
            });
        } else {
            leftFixedElement = this.leftFixedElement = doc.createElement('div');
            leftFixedElement.className = 'left-fixed';
            leftFixedElement.style.cssText = 'top: 0; left: 0; height: 100%;';
            /**
         * @member leftElement
         * @instance
         * @memberOf ctrl.scrollview~Fixed
         * @description 固定在左边的元素
         * @type {HTMLElement}
         */
            Object.defineProperty(that, 'leftElement', {
                get: function() {
                    return leftFixedElement;
                },
                set: function(v) {
                    setHTMLElement(leftFixedElement, v);
                }
            });
            /**
         * @member leftOffset
         * @instance
         * @memberOf ctrl.scrollview~Fixed
         * @description 离左边的距离
         * @type {Number}
         */
            Object.defineProperty(that, 'leftOffset', {
                set: function(v) {
                    leftFixedElement.style.left = v + 'px';
                }
            });
            rightFixedElement = this.rightFixedElement = doc.createElement('div');
            rightFixedElement.className = 'right-fxied';
            rightFixedElement.style.cssText = 'top: 0; right: 0; height: 100%;';
            /**
         * @member rightElement
         * @instance
         * @memberOf ctrl.scrollview~Fixed
         * @description 固定在右边的元素
         * @type {HTMLElement}
         */
            Object.defineProperty(that, 'rightElement', {
                get: function() {
                    return rightFixedElement;
                },
                set: function(v) {
                    setHTMLElement(rightFixedElement, v);
                }
            });
            /**
         * @member rightOffset
         * @instance
         * @memberOf ctrl.scrollview~Fixed
         * @description 离右边的距离
         * @type {Number}
         */
            Object.defineProperty(that, 'rightOffset', {
                set: function(v) {
                    rightFixedElement.style.right = v + 'px';
                }
            });
        }
    }
    /**
 * 图片懒加载的插件
 * @class ctrl.scrollview~Lazyload
 * @param {ctrl.scrollview~ScrollView} view 视图对象实例
 * @return {ctrl.scrollview~Lazyload} 实例
 */
    function Lazyload(view) {
        var that = this;
        var scroll = view.scroll;
        var limit = 4;
        var waitingQueue = [];
        var loadingCount = 0;
        var loaded = {};
        var isRunningLoadingQueue = false;
        function runLoadingQueue() {
            if (isRunningLoadingQueue)
                return;
            isRunningLoadingQueue = true;
            if (loadingCount < limit && waitingQueue.length > 0) {
                var url = waitingQueue.shift();
                loadingCount++;
                var img = new Image();
                img.onload = img.onreadystatechange = function() {
                    if (loaded[url] !== true) {
                        loaded[url].forEach(function(cb) {
                            cb && cb(url);
                        });
                        loaded[url] = true;
                        loadingCount--;
                    }
                    runLoadingQueue();
                }
                img.src = url;
                runLoadingQueue();
            }
            isRunningLoadingQueue = false;
        }
        function load(url, callback) {
            if (loaded[url] === true) {
                return callback(url);
            } else if (loaded[url]) {
                loaded[url].push(callback);
            } else {
                loaded[url] = [callback];
                waitingQueue.push(url);
            }
            runLoadingQueue();
        }
        function checkLazyload() {
            if (!enable)
                return;
            var elements = Array.prototype.slice.call(scroll.element.querySelectorAll('.lazy, *[lazyload="true"]'));
            elements.filter(function(el) {
                return scroll.isInView(el);
            }).forEach(function(el) {
                var imglist;
                var bglist;
                if (el.tagName.toUpperCase() === 'IMG') {
                    imglist = [el];
                    bglist = [];
                } else {
                    imglist = Array.prototype.slice.call(el.querySelectorAll('img[data-src]'));
                    bglist = Array.prototype.slice.call(el.querySelectorAll('*[data-image]'));
                    if (el.hasAttribute('data-image')) {
                        bglist.push(el);
                    }
                }
                imglist.forEach(function(img) {
                    var src = img.getAttribute('data-src');
                    if (src) {
                        img.removeAttribute('data-src');
                        load(src, function() {
                            img.src = src;
                        });
                    }
                });
                bglist.forEach(function(bg) {
                    var image = bg.getAttribute('data-image');
                    if (image) {
                        bg.removeAttribute('data-image');
                        load(image, function() {
                            bg.style.backgroundImage = 'url(' + image + ')';
                        });
                    }
                });
                lazyloadHandler && lazyloadHandler(el);
                el.className = el.className.split(' ').filter(function(name) {
                    return name !== 'lazy'
                }).join(' ');
                el.removeAttribute('lazyload');
            });
        }
        var enable;
        /**
     * @member enable
     * @instance
     * @memberOf ctrl.scrollview~Lazyload
     * @description 启用懒加载
     * @type {Boolean}
     */
        Object.defineProperty(that, 'enable', {
            get: function() {
                return enable;
            },
            set: function(v) {
                enable = v;
            }
        });
        var lazyloadHandler;
        /**
     * @member handler
     * @instance
     * @memberOf ctrl.scrollview~Lazyload
     * @description 懒加载发生时的句柄
     * @type {Function}
     */
        Object.defineProperty(that, 'handler', {
            get: function() {
                return lazyloadHandler;
            },
            set: function(v) {
                lazyloadHandler = v;
            }
        });
        var realtime;
        /**
     * @member handler
     * @instance
     * @memberOf ctrl.scrollview~Lazyload
     * @description 是否在滚动时实时发生懒加载
     * @type {Boolean}
     */
        Object.defineProperty(that, 'realtime', {
            get: function() {
                return realtime;
            },
            set: function(v) {
                realtime = !!v;
                if (realtime) {// view.forceRepaint.enable = true;
                }
            }
        });
        scroll.addScrollingHandler(function() {
            if (realtime) {
                checkLazyload();
            }
        });
        scroll.addScrollendHandler(function() {
            checkLazyload();
        });
        scroll.addContentrenfreshHandler(function() {
            checkLazyload();
        });
        lib.animation.requestFrame(function() {
            checkLazyload();
        });
        /**
     * @method checkLazyload
     * @instance
     * @memberOf ctrl.scrollview~Lazyload
     * @description 触发懒加载
     */
        view.checkLazyload = checkLazyload;
    }
    /**
 * 元素吸顶的插件
 * @class ctrl.scrollview~Sticky
 * @param {ctrl.scrollview~ScrollView} view 视图对象实例
 * @return {ctrl.scrollview~Sticky} 实例
 */
    function Sticky(view) {
        var that = this;
        var scroll = view.scroll;
        var stickyWrapElement = doc.createElement('div');
        stickyWrapElement.className = 'sticky';
        stickyWrapElement.style.cssText = 'z-index:9; position: absolute; left: 0; top: 0;' + cssPrefix + 'transform: translateZ(9px);';
        if (scroll.axis === 'y') {
            stickyWrapElement.style.width = '100%';
        } else {
            stickyWrapElement.style.height = '100%';
        }
        /**
     * @member offset
     * @instance
     * @memberOf ctrl.scrollview~Sticky
     * @description 吸顶元素的偏移值
     * @type {Number}
     */
        Object.defineProperty(this, 'offset', {
            set: function(v) {
                if (scroll.axis === 'y') {
                    stickyWrapElement.style.top = v + 'px';
                } else {
                    stickyWrapElement.style.left = v + 'px';
                }
            }
        });
        var enable;
        /**
     * @member enable
     * @instance
     * @memberOf ctrl.scrollview~Sticky
     * @description 启用吸顶
     * @type {Boolean}
     */
        Object.defineProperty(this, 'enable', {
            get: function() {
                return enable;
            },
            set: function(v) {
                enable = !!v;
                if (enable) {
                    if (!stickyWrapElement.parentNode) {
                        scroll.viewport.appendChild(stickyWrapElement);
                    }
                    stickyWrapElement.style.display = 'block';
                } else {
                    stickyWrapElement.style.display = 'none';
                }
            }
        });
        var stickyList = [];
        function checkSticky() {
            if (!enable)
                return;
            Array.prototype.slice.call(scroll.element.querySelectorAll('.sticky, *[sticky="true"]')).forEach(function(el) {
                el.className = el.className.split(' ').filter(function(name) {
                    return name !== 'sticky'
                }).join(' ');
                el.setAttribute('sticky', 'initialized');
                var offset = scroll.offset(el);
                var top = offset.top;
                for (var i = 0; i <= stickyList.length; i++) {
                    if (!stickyList[i] || top < stickyList[i].top) {
                        stickyList.splice(i, 0, {
                            top: top,
                            el: el,
                            pined: el.firstElementChild
                        });
                        break;
                    }
                }
            });
            if (stickyList.length) {
                var scrollOffset = scroll.axis === 'y' ? scroll.getScrollTop() : scroll.getScrollLeft();
                for (var i = 0; i < stickyList.length; i++) {
                    if (scrollOffset < stickyList[i][scroll.axis === 'y' ? 'top' : 'left']) {
                        break;
                    }
                }
                j = i - 1;
                if (j > -1) {
                    if (!stickyList[j].pined.parentNode || stickyList[j].pined.parentNode === stickyList[j].el) {
                        stickyWrapElement.innerHTML = '';
                        stickyWrapElement.appendChild(stickyList[j].pined);
                    }
                }
                for (j++; j < stickyList.length; j++) {
                    if (stickyList[j].pined.parentNode !== stickyList[j].el) {
                        stickyList[j].el.appendChild(stickyList[j].pined);
                    }
                }
            }
        }
        // view.forceRepaint.enable = true;
        scroll.addScrollingHandler(checkSticky);
        scroll.addScrollendHandler(checkSticky);
        /**
     * @method checkSticky
     * @instance
     * @memberOf ctrl.scrollview~Sticky
     * @description 触发吸顶
     * @type {Number}
     */
        view.checkSticky = checkSticky;
    }
    /**
 * 下拉刷新的插件
 * @class ctrl.scrollview~Refresh
 * @param {ctrl.scrollview~ScrollView} view 视图对象实例
 * @return {ctrl.scrollview~Refresh} 实例
 */
    function Refresh(view) {
        var that = this;
        var scroll = view.scroll;
        var refreshElement = doc.createElement('div');
        refreshElement.className = 'refresh';
        refreshElement.style.cssText = 'display: none; position: absolute; top: 0; left: 0; width: 0; height: 0; ' + cssPrefix + 'transform: translateZ(9px)';
        if (scroll.axis === 'y') {
            refreshElement.style.width = '100%';
        } else {
            refreshElement.style.height = '100%';
        }
        var enable = false;
        /**
     * @member enable
     * @instance
     * @memberOf ctrl.scrollview~Refresh
     * @description 启用下拉刷新
     * @type {Boolean}
     */
        Object.defineProperty(this, 'enable', {
            get: function() {
                return enable;
            },
            set: function(v) {
                enable = v;
                if (!!enable) {
                    if (!refreshElement.parentNode) {
                        scroll.viewport.appendChild(refreshElement);
                    }
                    refreshElement.style.display = 'block';
                } else {
                    refreshElement.style.display = 'none';
                }
            }
        });
        /**
     * @member element
     * @instance
     * @memberOf ctrl.scrollview~Refresh
     * @description 下拉刷新的动画元素
     * @type {HTMLElement}
     */
        Object.defineProperty(this, 'element', {
            get: function() {
                return refreshElement;
            },
            set: function(v) {
                setHTMLElement(refreshElement, v);
            }
        });
        /**
     * @member offset
     * @instance
     * @memberOf ctrl.scrollview~Refresh
     * @description 下拉刷新的动画元素的偏移值
     * @type {Number}
     */
        Object.defineProperty(this, 'offset', {
            set: function(v) {
                if (scroll.axis === 'y') {
                    refreshElement.style.top = v + 'px';
                } else {
                    refreshElement.style.left = v + 'px';
                }
            }
        });
        var width = 0;
        /**
     * @member width
     * @instance
     * @memberOf ctrl.scrollview~Refresh
     * @description 下拉刷新的动画元素的宽度
     * @type {Number}
     */
        Object.defineProperty(this, 'width', {
            set: function(v) {
                width = v;
                if (scroll.axis === 'x') {
                    refreshElement.style.width = width + 'px';
                    refreshElement.style[stylePrefix + 'Transform'] = 'translateX(' + (-width) + 'px) translateZ(9px)';
                }
            }
        });
        var height = 0;
        /**
     * @member height
     * @instance
     * @memberOf ctrl.scrollview~Refresh
     * @description 下拉刷新的动画元素的高度
     * @type {Number}
     */
        Object.defineProperty(this, 'height', {
            set: function(v) {
                height = v;
                if (scroll.axis === 'y') {
                    refreshElement.style.height = height + 'px';
                    refreshElement.style[stylePrefix + 'Transform'] = 'translateY(' + (-height) + 'px) translateZ(9px)';
                }
            }
        });
        var processingHandler;
        /**
     * @member processingHandler
     * @instance
     * @memberOf ctrl.scrollview~Refresh
     * @description 下拉中的事件句柄
     * @type {Function}
     */
        Object.defineProperty(this, 'processingHandler', {
            get: function() {
                return processingHandler;
            },
            set: function(v) {
                processingHandler = v;
            }
        });
        var refreshHandler;
        /**
     * @member refreshHandler
     * @instance
     * @memberOf ctrl.scrollview~Refresh
     * @description 下拉结束后的事件句柄
     * @type {Function}
     */
        Object.defineProperty(this, 'refreshHandler', {
            get: function() {
                return refreshHandler;
            },
            set: function(v) {
                refreshHandler = v;
            }
        });
        var isRefresh;
        scroll.addScrollingHandler(function(e) {
            if (!enable || isRefresh)
                return;
            var offset = scroll.axis === 'y' ? scroll.getScrollTop() : scroll.getScrollLeft();
            offset = Math.min(offset, 0);
            if (scroll.axis === 'y') {
                refreshElement.style[stylePrefix + 'Transform'] = 'translateY(' + -(height + offset) + 'px) translateZ(9px)';
            } else {
                refreshElement.style[stylePrefix + 'Transform'] = 'translateX(' + -(width + offset) + 'px) translateZ(9px)';
            }
            if (offset < 0) {
                processingHandler && processingHandler(-offset);
            }
        });
        function pullingAnimation(callback) {
            var refreshOffset = getTransformOffset(refreshElement)[scroll.axis];
            var refreshDiff = 0 - refreshOffset;
            var elementOffset = getTransformOffset(scroll.element)[scroll.axis];
            var elementDiff = (scroll.axis === 'y' ? height : width) - elementOffset;
            new lib.animation(400,lib.cubicbezier.ease,function(i1, i2) {
                refreshElement.style[stylePrefix + 'Transform'] = 'translate' + scroll.axis.toUpperCase() + '(' + (refreshOffset + refreshDiff * i2) + 'px) translateZ(9px)';
                scroll.element.style[stylePrefix + 'Transform'] = 'translate' + scroll.axis.toUpperCase() + '(' + (elementOffset + elementDiff * i2) + 'px)';
            }
            ).play().then(callback);
        }
        function reboundAnimation(callback) {
            var refreshOffset = getTransformOffset(refreshElement)[scroll.axis];
            var refreshDiff = -(scroll.axis === 'y' ? height : width) - refreshOffset;
            var elementOffset = getTransformOffset(scroll.element)[scroll.axis];
            var elementDiff = -elementOffset;
            new lib.animation(400,lib.cubicbezier.ease,function(i1, i2) {
                refreshElement.style[stylePrefix + 'Transform'] = 'translate' + scroll.axis.toUpperCase() + '(' + (refreshOffset + refreshDiff * i2) + 'px) translateZ(9px)';
                scroll.element.style[stylePrefix + 'Transform'] = 'translate' + scroll.axis.toUpperCase() + '(' + (elementOffset + elementDiff * i2) + 'px)';
            }
            ).play().then(callback);
        }
        scroll.addEventListener('pulldownend', function(e) {
            if (!enable || isRefresh)
                return;
            isRefresh = true;
            var offset = scroll.getBoundaryOffset();
            if (offset > (scroll.axis === 'y' ? height : width)) {
                scroll.disable();
                pullingAnimation(function() {
                    if (refreshHandler) {
                        refreshHandler(function() {
                            reboundAnimation(function() {
                                scroll.refresh();
                                scroll.enable();
                                isRefresh = false;
                            });
                        });
                    } else {
                        reboundAnimation(function() {
                            scroll.refresh();
                            scroll.enable();
                            isRefresh = false;
                        });
                    }
                });
            } else {
                reboundAnimation(function() {
                    isRefresh = false;
                });
            }
        }, false);
    }
    /**
 * 上拉更新的插件
 * @class ctrl.scrollview~Update
 * @param {ctrl.scrollview~ScrollView} view 视图对象实例
 * @return {ctrl.scrollview~Update} 实例
 */
    function Update(view) {
        var that = this;
        var scroll = view.scroll;
        var updateElement = doc.createElement('div');
        updateElement.className = 'update';
        updateElement.style.cssText = 'display: none; position: absolute; bottom: 0; right: 0; width: 0; height: 0; ' + cssPrefix + 'transform: translateZ(9px)';
        if (scroll.axis === 'y') {
            updateElement.style.width = '100%';
        } else {
            updateElement.style.height = '100%';
        }
        var enable = false;
        /**
     * @member enable
     * @instance
     * @memberOf ctrl.scrollview~Update
     * @description 启用上拉更新
     * @type {Boolean}
     */
        Object.defineProperty(this, 'enable', {
            get: function() {
                return enable;
            },
            set: function(v) {
                enable = v;
                if (!!enable) {
                    if (!updateElement.parentNode) {
                        scroll.viewport.appendChild(updateElement);
                    }
                    updateElement.style.display = 'block';
                } else {
                    updateElement.style.display = 'none';
                }
            }
        });
        /**
     * @member element
     * @instance
     * @memberOf ctrl.scrollview~Update
     * @description 上拉更新的动画元素
     * @type {HTMLElement}
     */
        Object.defineProperty(this, 'element', {
            get: function() {
                return updateElement;
            },
            set: function(v) {
                setHTMLElement(updateElement, v);
            }
        });
        /**
     * @member offset
     * @instance
     * @memberOf ctrl.scrollview~Update
     * @description 上拉更新的动画元素的偏移值
     * @type {Number}
     */
        Object.defineProperty(this, 'offset', {
            set: function(v) {
                if (scroll.axis === 'y') {
                    updateElement.style.bottom = v + 'px';
                } else {
                    updateElement.style.right = v + 'px';
                }
            }
        });
        var width = 0;
        /**
     * @member width
     * @instance
     * @memberOf ctrl.scrollview~Update
     * @description 上拉更新的动画元素的宽度
     * @type {Number}
     */
        Object.defineProperty(this, 'width', {
            set: function(v) {
                width = v;
                if (scroll.axis === 'x') {
                    updateElement.style.width = width + 'px';
                    updateElement.style[stylePrefix + 'Transform'] = 'translateX(' + (width) + 'px) translateZ(9px)';
                }
            }
        });
        var height = 0;
        /**
     * @member height
     * @instance
     * @memberOf ctrl.scrollview~Update
     * @description 上拉更新的动画元素的高度
     * @type {Number}
     */
        Object.defineProperty(this, 'height', {
            set: function(v) {
                height = v;
                if (scroll.axis === 'y') {
                    updateElement.style.height = height + 'px';
                    updateElement.style[stylePrefix + 'Transform'] = 'translateY(' + (height) + 'px) translateZ(9px)';
                }
            }
        });
        var processingHandler;
        /**
     * @member processingHandler
     * @instance
     * @memberOf ctrl.scrollview~Update
     * @description 上拉中的事件句柄
     * @type {Function}
     */
        Object.defineProperty(this, 'processingHandler', {
            get: function() {
                return processingHandler;
            },
            set: function(v) {
                processingHandler = v;
            }
        });
        var updateHandler;
        /**
     * @member updateHandler
     * @instance
     * @memberOf ctrl.scrollview~Update
     * @description 上拉结束时的事件句柄
     * @type {Function}
     */
        Object.defineProperty(this, 'updateHandler', {
            get: function() {
                return updateHandler;
            },
            set: function(v) {
                updateHandler = v;
            }
        });
        var isUpdating;
        scroll.addScrollingHandler(function(e) {
            if (!enable)
                return;
            var offset = scroll.axis === 'y' ? scroll.getScrollTop() : scroll.getScrollLeft();
            var maxOffset = scroll.axis === 'y' ? scroll.getMaxScrollTop() : scroll.getMaxScrollLeft();
            offset = Math.max(offset, maxOffset);
            if (scroll.axis === 'y') {
                updateElement.style[stylePrefix + 'Transform'] = 'translateY(' + (maxOffset - offset + height) + 'px) translateZ(9px)';
            } else {
                updateElement.style[stylePrefix + 'Transform'] = 'translateX(' + (maxOffset - offset + width) + 'px) translateZ(9px)';
            }
            if (isUpdating)
                return;
            if (offset - maxOffset < (scroll.axis === 'y' ? height : width) * 0.7) {
                processingHandler && processingHandler(offset - maxOffset);
            } else {
                if (updateHandler) {
                    isUpdating = true;
                    updateHandler(function() {
                        if (scroll.axis === 'y') {
                            updateElement.style[stylePrefix + 'Transform'] = 'translateY(' + (height) + 'px) translateZ(9px)';
                        } else {
                            updateElement.style[stylePrefix + 'Transform'] = 'translateX(' + (width) + 'px) translateZ(9px)';
                        }
                        scroll.refresh();
                        isUpdating = false;
                    });
                }
            }
        });
    }
    /**
 * @namespace ctrl
 */
    /**
 * @method scrollview
 * @memberOf ctrl
 * @param {HTMLElement} root 滚动视图的根元素
 * @param {Obejct} [options] 设置，同`lib.scroll`的设置
 * @return {ctrl.scrollview~ScrollView} ScrollView的实例
 */
    ctrl.scrollview = function(root, options) {
        return new ScrollView(root,options);
    }
})(window, window['lib'], window['ctrl'] || (window['ctrl'] = {}));
!function() {
    var a = "[data-ctrl-name=scrollview]{width:100%;height:100%;overflow:hidden;display:-webkit-box;display:-moz-box;display:-ms-flexbox;display:-webkit-flex;display:flex}[data-ctrl-name=scrollview][data-direction=vertical]{-webkit-box-orient:vertical;-webkit-box-direction:normal;-moz-box-orient:vertical;-moz-box-direction:normal;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column}[data-ctrl-name=scrollview][data-direction=horizontal]{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-moz-box-orient:horizontal;-moz-box-direction:normal;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row}[data-ctrl-name=scrollview] .scroll-wrap{display:block;-webkit-box-flex:1;-moz-box-flex:1;-webkit-flex:1;-ms-flex:1;flex:1;overflow:hidden;position:relative}[data-ctrl-name=scrollview][data-direction=vertical] .scroll-wrap,[data-ctrl-name=scrollview][data-direction=vertical] .scroll-content{width:100%}[data-ctrl-name=scrollview][data-direction=horizontal] .scroll-wrap,[data-ctrl-name=scrollview][data-direction=horizontal] .scroll-content{height:100%}[data-ctrl-name=scrollview] .scroll-content{position:absolute}"
      , b = document.createElement("style");
    if (document.getElementsByTagName("head")[0].appendChild(b),
    b.styleSheet)
        b.styleSheet.disabled || (b.styleSheet.cssText = a);
    else
        try {
            b.innerHTML = a
        } catch (c) {
            b.innerText = a
        }
}();
